From fc570b9e2ec30c120142cafe0313b369d41eb188 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 22 Feb 2017 11:59:50 -0400 Subject: [PATCH 001/291] JSR-354 Java Money & Currency --- .../.resourceCache/ECBCurrentRateProvider.dat | 42 +++++ .../ECBHistoric90RateProvider.dat | 63 ++++++++ .../IMFHistoricRateProvider.dat | 118 ++++++++++++++ core-java/.resourceCache/IMFRateProvider.dat | 118 ++++++++++++++ core-java/pom.xml | 6 + .../java/com/baeldung/money/JavaMoney.java | 147 ++++++++++++++++++ .../com/baeldung/money/JavaMoneyTest.java | 58 +++++++ 7 files changed, 552 insertions(+) create mode 100644 core-java/.resourceCache/ECBCurrentRateProvider.dat create mode 100644 core-java/.resourceCache/ECBHistoric90RateProvider.dat create mode 100644 core-java/.resourceCache/IMFHistoricRateProvider.dat create mode 100644 core-java/.resourceCache/IMFRateProvider.dat create mode 100644 core-java/src/main/java/com/baeldung/money/JavaMoney.java create mode 100644 core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java diff --git a/core-java/.resourceCache/ECBCurrentRateProvider.dat b/core-java/.resourceCache/ECBCurrentRateProvider.dat new file mode 100644 index 0000000000..37d1d8c8ab --- /dev/null +++ b/core-java/.resourceCache/ECBCurrentRateProvider.dat @@ -0,0 +1,42 @@ + + + Reference rates + + European Central Bank + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-java/.resourceCache/ECBHistoric90RateProvider.dat b/core-java/.resourceCache/ECBHistoric90RateProvider.dat new file mode 100644 index 0000000000..16edc6a30a --- /dev/null +++ b/core-java/.resourceCache/ECBHistoric90RateProvider.dat @@ -0,0 +1,63 @@ +Reference ratesEuropean Central Bank + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-java/.resourceCache/IMFHistoricRateProvider.dat b/core-java/.resourceCache/IMFHistoricRateProvider.dat new file mode 100644 index 0000000000..1db358b58b --- /dev/null +++ b/core-java/.resourceCache/IMFHistoricRateProvider.dat @@ -0,0 +1,118 @@ +SDRs per Currency unit and Currency units per SDR (1) +last five days +SDRs per Currency unit (2) + +Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 +Chinese Yuan 0.1077740000 0.1075920000 0.1074250000 0.1075990000 0.1078580000 +Euro 0.7806080000 0.7860480000 0.7864600000 0.7819020000 +Japanese Yen 0.0065267800 0.0065271000 0.0065062900 0.0064850300 0.0064793800 +U.K. Pound Sterling 0.9217470000 0.9201430000 0.9163910000 0.9224580000 0.9204290000 +U.S. Dollar 0.7413120000 0.7408260000 0.7380730000 0.7383210000 0.7407880000 +Algerian Dinar 0.0067122300 0.0067137500 0.0067192300 0.0067098500 +Australian Dollar 0.5680650000 0.5689800000 0.5694670000 0.5682580000 +Bahrain Dinar 1.9702800000 1.9629600000 1.9636200000 1.9701800000 +Botswana Pula 0.0708970000 0.0709288000 0.0712480000 0.0711156000 +Brazilian Real 0.2396560000 0.2419590000 0.2399250000 0.2389790000 +Brunei Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 +Canadian Dollar 0.5634090000 0.5627270000 0.5661790000 +Chilean Peso 0.0011535600 0.0011562200 0.0011537500 +Colombian Peso 0.0002552100 0.0002566600 0.0002567150 0.0002583270 +Czech Koruna 0.0288889000 0.0290901000 0.0291136000 +Danish Krone 0.1050150000 0.1057460000 0.1057900000 0.1051720000 +Hungarian Forint 0.0025387300 0.0025516800 0.0025498900 0.0025358200 +Icelandic Krona 0.0066885700 0.0066860500 0.0066725800 0.0066218600 +Indian Rupee 0.0110083000 0.0110285000 0.0110699000 +Indonesian Rupiah 0.0000554096 0.0000553776 0.0000553921 +Iranian Rial 0.0000228671 0.0000227947 0.0000228695 +Israeli New Sheqel 0.1998450000 0.1986200000 0.1986870000 0.1977020000 +Kazakhstani Tenge 0.0023350800 0.0023165400 0.0023114400 0.0023099100 +Korean Won 0.0006455440 0.0006480580 0.0006467420 0.0006472590 +Kuwaiti Dinar 2.4257600000 2.4171400000 2.4179500000 2.4248400000 +Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 +Malaysian Ringgit 0.1661230000 0.1655610000 0.1656540000 0.1664690000 +Mauritian Rupee 0.0207521000 0.0207775000 0.0208634000 +Mexican Peso 0.0360870000 0.0364464000 +Nepalese Rupee 0.0069139200 0.0068914400 0.0068937500 0.0069148500 +New Zealand Dollar 0.5306540000 0.5322980000 0.5342490000 0.5300340000 +Norwegian Krone 0.0885668000 0.0886734000 0.0886755000 0.0883278000 +Rial Omani 1.9267300000 1.9195700000 1.9202100000 1.9266300000 +Pakistani Rupee 0.0070658600 0.0070405000 0.0070429300 0.0070671000 +Nuevo Sol 0.2264720000 +Philippine Peso 0.0147628000 0.0147836000 0.0148472000 +Polish Zloty 0.1809450000 0.1813760000 0.1820000000 0.1817800000 +Qatar Riyal 0.2035240000 0.2027670000 0.2028350000 0.2035130000 +Russian Ruble 0.0128040000 0.0128062000 0.0129188000 0.0130485000 +Saudi Arabian Riyal 0.1975540000 0.1968190000 0.1968860000 0.1975430000 +Singapore Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 +South African Rand 0.0562263000 0.0562860000 0.0569367000 0.0568608000 +Sri Lanka Rupee 0.0049020900 0.0048960700 0.0048979200 0.0049141600 +Swedish Krona 0.0824973000 0.0830639000 0.0829146000 0.0828400000 +Swiss Franc 0.7337090000 0.7385900000 0.7376570000 0.7341080000 +Thai Baht 0.0211393000 0.0210914000 0.0210961000 0.0211545000 +Trinidad And Tobago Dollar 0.1095510000 0.1093120000 0.1094000000 0.1097660000 +Tunisian Dinar 0.3234230000 0.3229230000 0.3212750000 0.3239130000 +U.A.E. Dirham 0.2017230000 0.2009730000 0.2010400000 0.2017120000 +Peso Uruguayo 0.0260937000 0.0260969000 +Bolivar Fuerte 0.0740171000 0.0742645000 + +Currency units per SDR(3) + +Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 +Chinese Yuan 9.278680 9.294370 9.308820 9.293770 9.271450 +Euro 1.281050 1.272190 1.271520 1.278930 +Japanese Yen 153.215000 153.207000 153.697000 154.201000 154.336000 +U.K. Pound Sterling 1.084900 1.086790 1.091240 1.084060 1.086450 +U.S. Dollar 1.348960 1.349840 1.354880 1.354420 1.349910 +Algerian Dinar 148.982000 148.948000 148.827000 149.035000 +Australian Dollar 1.760360 1.757530 1.756030 1.759760 +Bahrain Dinar 0.507542 0.509435 0.509264 0.507568 +Botswana Pula 14.105000 14.098600 14.035500 14.061600 +Brazilian Real 4.172650 4.132930 4.167970 4.184470 +Brunei Dollar 1.917730 1.920410 1.922470 1.915930 +Canadian Dollar 1.774910 1.777060 1.766230 +Chilean Peso 866.882000 864.887000 866.739000 +Colombian Peso 3,918.340000 3,896.210000 3,895.370000 3,871.060000 +Czech Koruna 34.615400 34.376000 34.348200 +Danish Krone 9.522450 9.456620 9.452690 9.508230 +Hungarian Forint 393.898000 391.899000 392.174000 394.350000 +Icelandic Krona 149.509000 149.565000 149.867000 151.015000 +Indian Rupee 90.840500 90.674200 90.335100 +Indonesian Rupiah 18,047.400000 18,057.800000 18,053.100000 +Iranian Rial 43,730.900000 43,869.800000 43,726.400000 +Israeli New Sheqel 5.003880 5.034740 5.033040 5.058120 +Kazakhstani Tenge 428.251000 431.678000 432.631000 432.917000 +Korean Won 1,549.080000 1,543.070000 1,546.210000 1,544.980000 +Kuwaiti Dinar 0.412242 0.413712 0.413573 0.412398 +Libyan Dinar 1.932400 1.932400 1.932400 1.932400 +Malaysian Ringgit 6.019640 6.040070 6.036680 6.007120 +Mauritian Rupee 48.187900 48.129000 47.930800 +Mexican Peso 27.710800 27.437600 +Nepalese Rupee 144.636000 145.108000 145.059000 144.616000 +New Zealand Dollar 1.884470 1.878650 1.871790 1.886670 +Norwegian Krone 11.290900 11.277300 11.277100 11.321500 +Rial Omani 0.519014 0.520950 0.520776 0.519041 +Pakistani Rupee 141.526000 142.035000 141.986000 141.501000 +Nuevo Sol 4.415560 +Philippine Peso 67.737800 67.642500 67.352800 +Polish Zloty 5.526540 5.513410 5.494510 5.501160 +Qatar Riyal 4.913430 4.931770 4.930120 4.913690 +Russian Ruble 78.100600 78.087200 77.406600 76.637200 +Saudi Arabian Riyal 5.061910 5.080810 5.079080 5.062190 +Singapore Dollar 1.917730 1.920410 1.922470 1.915930 +South African Rand 17.785300 17.766400 17.563400 17.586800 +Sri Lanka Rupee 203.995000 204.245000 204.168000 203.494000 +Swedish Krona 12.121600 12.038900 12.060600 12.071500 +Swiss Franc 1.362940 1.353930 1.355640 1.362200 +Thai Baht 47.305300 47.412700 47.402100 47.271300 +Trinidad And Tobago Dollar 9.128170 9.148130 9.140770 9.110290 +Tunisian Dinar 3.091930 3.096710 3.112600 3.087250 +U.A.E. Dirham 4.957290 4.975790 4.974130 4.957560 +Peso Uruguayo 38.323400 38.318700 +Bolivar Fuerte 13.510400 13.465400 + + +(1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. + +(2) The value of the U.S. dollar in terms of the SDR is the reciprocal of the sum of the dollar values, based on market exchange rates, of specified quantities of the SDR basket currencies. See SDR Valuation.The value in terms of the SDR of each of the other currencies shown above is derived from that currency's representative exchange rate against the U.S. dollar as reported by the issuing central bank and the SDR value of the U.S. dollar, except for the Iranian rial and the Libyan dinar, the values of which are officially expressed directly in terms of domestic currency units per SDR. All figures are rounded to six significant digits. See Representative Exchange Rates for Selected Currencies". + +(3) The value in terms of each national currency of the SDR is the reciprocal of the value in terms of the SDR of each national currency, rounded to six significant digits. \ No newline at end of file diff --git a/core-java/.resourceCache/IMFRateProvider.dat b/core-java/.resourceCache/IMFRateProvider.dat new file mode 100644 index 0000000000..1db358b58b --- /dev/null +++ b/core-java/.resourceCache/IMFRateProvider.dat @@ -0,0 +1,118 @@ +SDRs per Currency unit and Currency units per SDR (1) +last five days +SDRs per Currency unit (2) + +Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 +Chinese Yuan 0.1077740000 0.1075920000 0.1074250000 0.1075990000 0.1078580000 +Euro 0.7806080000 0.7860480000 0.7864600000 0.7819020000 +Japanese Yen 0.0065267800 0.0065271000 0.0065062900 0.0064850300 0.0064793800 +U.K. Pound Sterling 0.9217470000 0.9201430000 0.9163910000 0.9224580000 0.9204290000 +U.S. Dollar 0.7413120000 0.7408260000 0.7380730000 0.7383210000 0.7407880000 +Algerian Dinar 0.0067122300 0.0067137500 0.0067192300 0.0067098500 +Australian Dollar 0.5680650000 0.5689800000 0.5694670000 0.5682580000 +Bahrain Dinar 1.9702800000 1.9629600000 1.9636200000 1.9701800000 +Botswana Pula 0.0708970000 0.0709288000 0.0712480000 0.0711156000 +Brazilian Real 0.2396560000 0.2419590000 0.2399250000 0.2389790000 +Brunei Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 +Canadian Dollar 0.5634090000 0.5627270000 0.5661790000 +Chilean Peso 0.0011535600 0.0011562200 0.0011537500 +Colombian Peso 0.0002552100 0.0002566600 0.0002567150 0.0002583270 +Czech Koruna 0.0288889000 0.0290901000 0.0291136000 +Danish Krone 0.1050150000 0.1057460000 0.1057900000 0.1051720000 +Hungarian Forint 0.0025387300 0.0025516800 0.0025498900 0.0025358200 +Icelandic Krona 0.0066885700 0.0066860500 0.0066725800 0.0066218600 +Indian Rupee 0.0110083000 0.0110285000 0.0110699000 +Indonesian Rupiah 0.0000554096 0.0000553776 0.0000553921 +Iranian Rial 0.0000228671 0.0000227947 0.0000228695 +Israeli New Sheqel 0.1998450000 0.1986200000 0.1986870000 0.1977020000 +Kazakhstani Tenge 0.0023350800 0.0023165400 0.0023114400 0.0023099100 +Korean Won 0.0006455440 0.0006480580 0.0006467420 0.0006472590 +Kuwaiti Dinar 2.4257600000 2.4171400000 2.4179500000 2.4248400000 +Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 +Malaysian Ringgit 0.1661230000 0.1655610000 0.1656540000 0.1664690000 +Mauritian Rupee 0.0207521000 0.0207775000 0.0208634000 +Mexican Peso 0.0360870000 0.0364464000 +Nepalese Rupee 0.0069139200 0.0068914400 0.0068937500 0.0069148500 +New Zealand Dollar 0.5306540000 0.5322980000 0.5342490000 0.5300340000 +Norwegian Krone 0.0885668000 0.0886734000 0.0886755000 0.0883278000 +Rial Omani 1.9267300000 1.9195700000 1.9202100000 1.9266300000 +Pakistani Rupee 0.0070658600 0.0070405000 0.0070429300 0.0070671000 +Nuevo Sol 0.2264720000 +Philippine Peso 0.0147628000 0.0147836000 0.0148472000 +Polish Zloty 0.1809450000 0.1813760000 0.1820000000 0.1817800000 +Qatar Riyal 0.2035240000 0.2027670000 0.2028350000 0.2035130000 +Russian Ruble 0.0128040000 0.0128062000 0.0129188000 0.0130485000 +Saudi Arabian Riyal 0.1975540000 0.1968190000 0.1968860000 0.1975430000 +Singapore Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 +South African Rand 0.0562263000 0.0562860000 0.0569367000 0.0568608000 +Sri Lanka Rupee 0.0049020900 0.0048960700 0.0048979200 0.0049141600 +Swedish Krona 0.0824973000 0.0830639000 0.0829146000 0.0828400000 +Swiss Franc 0.7337090000 0.7385900000 0.7376570000 0.7341080000 +Thai Baht 0.0211393000 0.0210914000 0.0210961000 0.0211545000 +Trinidad And Tobago Dollar 0.1095510000 0.1093120000 0.1094000000 0.1097660000 +Tunisian Dinar 0.3234230000 0.3229230000 0.3212750000 0.3239130000 +U.A.E. Dirham 0.2017230000 0.2009730000 0.2010400000 0.2017120000 +Peso Uruguayo 0.0260937000 0.0260969000 +Bolivar Fuerte 0.0740171000 0.0742645000 + +Currency units per SDR(3) + +Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 +Chinese Yuan 9.278680 9.294370 9.308820 9.293770 9.271450 +Euro 1.281050 1.272190 1.271520 1.278930 +Japanese Yen 153.215000 153.207000 153.697000 154.201000 154.336000 +U.K. Pound Sterling 1.084900 1.086790 1.091240 1.084060 1.086450 +U.S. Dollar 1.348960 1.349840 1.354880 1.354420 1.349910 +Algerian Dinar 148.982000 148.948000 148.827000 149.035000 +Australian Dollar 1.760360 1.757530 1.756030 1.759760 +Bahrain Dinar 0.507542 0.509435 0.509264 0.507568 +Botswana Pula 14.105000 14.098600 14.035500 14.061600 +Brazilian Real 4.172650 4.132930 4.167970 4.184470 +Brunei Dollar 1.917730 1.920410 1.922470 1.915930 +Canadian Dollar 1.774910 1.777060 1.766230 +Chilean Peso 866.882000 864.887000 866.739000 +Colombian Peso 3,918.340000 3,896.210000 3,895.370000 3,871.060000 +Czech Koruna 34.615400 34.376000 34.348200 +Danish Krone 9.522450 9.456620 9.452690 9.508230 +Hungarian Forint 393.898000 391.899000 392.174000 394.350000 +Icelandic Krona 149.509000 149.565000 149.867000 151.015000 +Indian Rupee 90.840500 90.674200 90.335100 +Indonesian Rupiah 18,047.400000 18,057.800000 18,053.100000 +Iranian Rial 43,730.900000 43,869.800000 43,726.400000 +Israeli New Sheqel 5.003880 5.034740 5.033040 5.058120 +Kazakhstani Tenge 428.251000 431.678000 432.631000 432.917000 +Korean Won 1,549.080000 1,543.070000 1,546.210000 1,544.980000 +Kuwaiti Dinar 0.412242 0.413712 0.413573 0.412398 +Libyan Dinar 1.932400 1.932400 1.932400 1.932400 +Malaysian Ringgit 6.019640 6.040070 6.036680 6.007120 +Mauritian Rupee 48.187900 48.129000 47.930800 +Mexican Peso 27.710800 27.437600 +Nepalese Rupee 144.636000 145.108000 145.059000 144.616000 +New Zealand Dollar 1.884470 1.878650 1.871790 1.886670 +Norwegian Krone 11.290900 11.277300 11.277100 11.321500 +Rial Omani 0.519014 0.520950 0.520776 0.519041 +Pakistani Rupee 141.526000 142.035000 141.986000 141.501000 +Nuevo Sol 4.415560 +Philippine Peso 67.737800 67.642500 67.352800 +Polish Zloty 5.526540 5.513410 5.494510 5.501160 +Qatar Riyal 4.913430 4.931770 4.930120 4.913690 +Russian Ruble 78.100600 78.087200 77.406600 76.637200 +Saudi Arabian Riyal 5.061910 5.080810 5.079080 5.062190 +Singapore Dollar 1.917730 1.920410 1.922470 1.915930 +South African Rand 17.785300 17.766400 17.563400 17.586800 +Sri Lanka Rupee 203.995000 204.245000 204.168000 203.494000 +Swedish Krona 12.121600 12.038900 12.060600 12.071500 +Swiss Franc 1.362940 1.353930 1.355640 1.362200 +Thai Baht 47.305300 47.412700 47.402100 47.271300 +Trinidad And Tobago Dollar 9.128170 9.148130 9.140770 9.110290 +Tunisian Dinar 3.091930 3.096710 3.112600 3.087250 +U.A.E. Dirham 4.957290 4.975790 4.974130 4.957560 +Peso Uruguayo 38.323400 38.318700 +Bolivar Fuerte 13.510400 13.465400 + + +(1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. + +(2) The value of the U.S. dollar in terms of the SDR is the reciprocal of the sum of the dollar values, based on market exchange rates, of specified quantities of the SDR basket currencies. See SDR Valuation.The value in terms of the SDR of each of the other currencies shown above is derived from that currency's representative exchange rate against the U.S. dollar as reported by the issuing central bank and the SDR value of the U.S. dollar, except for the Iranian rial and the Libyan dinar, the values of which are officially expressed directly in terms of domestic currency units per SDR. All figures are rounded to six significant digits. See Representative Exchange Rates for Selected Currencies". + +(3) The value in terms of each national currency of the SDR is the reciprocal of the value in terms of the SDR of each national currency, rounded to six significant digits. \ No newline at end of file diff --git a/core-java/pom.xml b/core-java/pom.xml index b2c59989f1..225eb3fc29 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -165,6 +165,12 @@ commons-codec ${commons-codec.version} + + + org.javamoney + moneta + 1.1 + diff --git a/core-java/src/main/java/com/baeldung/money/JavaMoney.java b/core-java/src/main/java/com/baeldung/money/JavaMoney.java new file mode 100644 index 0000000000..f66480bea5 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/money/JavaMoney.java @@ -0,0 +1,147 @@ +package com.baeldung.money; + +import java.util.Locale; +import java.util.logging.Logger; + +import javax.money.CurrencyUnit; +import javax.money.Monetary; +import javax.money.MonetaryAmount; +import javax.money.UnknownCurrencyException; +import javax.money.convert.ConversionQueryBuilder; +import javax.money.convert.CurrencyConversion; +import javax.money.convert.MonetaryConversions; +import javax.money.format.AmountFormatQueryBuilder; +import javax.money.format.MonetaryAmountFormat; +import javax.money.format.MonetaryFormats; + +import org.javamoney.moneta.FastMoney; +import org.javamoney.moneta.Money; +import org.javamoney.moneta.format.CurrencyStyle; + +public class JavaMoney { + final static Logger LOGGER = Logger.getLogger(JavaMoney.class.getName()); + CurrencyUnit USD; + MonetaryAmount fstAmtUSD; + MonetaryAmount fstAmtEUR; + MonetaryAmount oneDolar; + MonetaryAmount moneyof; + MonetaryAmount fastmoneyof; + MonetaryAmount roundEUR; + MonetaryAmount calcAmtUSD; + MonetaryAmount[] monetaryAmounts; + MonetaryAmount sumAmtCHF; + MonetaryAmount calcMoneyFastMoney; + MonetaryAmount convertedAmountEURtoUSD; + MonetaryAmount convertedAmountEURtoUSD2; + MonetaryAmount convertedAmountUSDtoEUR; + MonetaryAmount convertedAmountUSDtoEUR2; + MonetaryAmount multiplyAmount; + MonetaryAmount divideAmount; + MonetaryAmount oneDivThree; + CurrencyConversion convEUR; + CurrencyConversion convUSD; + CurrencyConversion conversionUSD; + CurrencyConversion conversionEUR; + MonetaryAmount oneEuro; + MonetaryAmountFormat formatUSD; + MonetaryAmountFormat customFormat; + String usFormatted; + String customFormatted; + + public JavaMoney() { + USD = Monetary.getCurrency("USD"); + fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); + fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + moneyof = Money.of(12, USD); + fastmoneyof = FastMoney.of(2, USD); + + LOGGER.info("First Amount in USD : " + fstAmtUSD); + LOGGER.info("First Amount in EUR : " + fstAmtEUR); + LOGGER.info("One Dolar : " + oneDolar); + LOGGER.info("MoneyOf : " + moneyof); + LOGGER.info("FastMoneyOf : " + fastmoneyof); + + try{ + @SuppressWarnings("unused") + CurrencyUnit AAA = Monetary.getCurrency("AAA"); + } catch (UnknownCurrencyException e) { + LOGGER.severe("Unknown Currency"); + } + + roundEUR = fstAmtEUR.with(Monetary.getDefaultRounding()); + + LOGGER.info("Rounded EUR : " + roundEUR); + + calcAmtUSD = Money.of(1, "USD").subtract(fstAmtUSD); + + LOGGER.info("Substracting amounts : " + calcAmtUSD); + + calcMoneyFastMoney = moneyof.subtract(fastmoneyof); + + LOGGER.info("Money & FastMoney operations : " + calcMoneyFastMoney); + + monetaryAmounts = new MonetaryAmount[] { Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF"), }; + sumAmtCHF = Money.of(0, "CHF"); + for (MonetaryAmount monetaryAmount : monetaryAmounts) { + sumAmtCHF = sumAmtCHF.add(monetaryAmount); + } + + LOGGER.info("Adding amounts : " + sumAmtCHF); + + multiplyAmount = oneDolar.multiply(0.25); + LOGGER.info("Multiply Amount : " + multiplyAmount); + + divideAmount = oneDolar.divide(0.25); + LOGGER.info("Divide Amount : " + divideAmount); + + try{ + oneDivThree = oneDolar.divide(3); + }catch (ArithmeticException e) { + LOGGER.severe("One divide by Three is an infinite number"); + } + + convEUR = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build()); + convUSD = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency(USD).build()); + + conversionUSD = MonetaryConversions.getConversion("USD"); + conversionEUR = MonetaryConversions.getConversion("EUR"); + + convertedAmountEURtoUSD = fstAmtEUR.with(conversionUSD); + convertedAmountEURtoUSD2 = fstAmtEUR.with(convUSD); + convertedAmountUSDtoEUR = oneDolar.with(conversionEUR); + convertedAmountUSDtoEUR2 = oneDolar.with(convEUR); + LOGGER.info("C1 - " + convertedAmountEURtoUSD); + LOGGER.info("C2 - " + convertedAmountEURtoUSD2); + LOGGER.info("One Euro -> " + convertedAmountUSDtoEUR); + LOGGER.info("One Euro2 -> " + convertedAmountUSDtoEUR2); + + oneEuro = Money.of(1, "EUR"); + + if (oneEuro.equals(FastMoney.of(1, "EUR"))) { + LOGGER.info("Money == FastMoney"); + } else { + LOGGER.info("Money != FastMoney"); + } + + if (oneDolar.equals(Money.of(1, "USD"))) { + LOGGER.info("Factory == Money"); + } else { + LOGGER.info("Factory != Money"); + } + + formatUSD = MonetaryFormats.getAmountFormat(Locale.US); + usFormatted = formatUSD.format(oneDolar); + LOGGER.info("One dolar standard formatted : " + usFormatted); + + customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern", "00000.00 ¤").build()); + customFormatted = customFormat.format(oneDolar); + LOGGER.info("One dolar custom formatted : " + customFormatted); + } + + public static void main(String[] args) { + @SuppressWarnings("unused") + JavaMoney java9Money = new JavaMoney(); + } + +} diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java new file mode 100644 index 0000000000..25fcd48f7a --- /dev/null +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -0,0 +1,58 @@ +package com.baeldung.money; + +import javax.money.convert.ConversionQueryBuilder; +import javax.money.convert.MonetaryConversions; + +import com.baeldung.money.JavaMoney; + +import junit.framework.TestCase; + +public class JavaMoneyTest + extends TestCase +{ + JavaMoney j9m; + public JavaMoneyTest( String testName ) + { + super( testName ); + j9m = new JavaMoney(); + } + + public void testAmounts() + { + assertEquals("USD", j9m.USD.toString()); + assertEquals("USD 1", j9m.oneDolar.toString()); + assertEquals("EUR 1", j9m.oneEuro.toString()); + assertEquals("USD 200.5", j9m.fstAmtUSD.toString()); + assertEquals("EUR 1.30473908", j9m.fstAmtEUR.toString()); + assertEquals("USD 12", j9m.moneyof.toString()); + assertEquals("USD 2.00000", j9m.fastmoneyof.toString()); + + } + + public void testArithmetic(){ + assertEquals("USD -199.5", j9m.calcAmtUSD.toString()); + assertEquals("CHF 111.35", j9m.sumAmtCHF.toString()); + assertEquals("USD 10", j9m.calcMoneyFastMoney.toString()); + assertEquals("USD 0.25", j9m.multiplyAmount.toString()); + assertEquals("USD 4", j9m.divideAmount.toString()); + } + + public void testRounding(){ + assertEquals("EUR 1.3", j9m.roundEUR.toString()); + } + + public void testFormatting(){ + assertEquals("USD1.00", j9m.usFormatted); + assertEquals("00001.00 US Dollar", j9m.customFormatted); + } + + public void testConversion(){ + + assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build())); + assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("USD").build())); + assertNotNull(j9m.convertedAmountEURtoUSD); + assertNotNull(j9m.convertedAmountEURtoUSD2); + assertNotNull(j9m.convertedAmountUSDtoEUR); + assertNotNull(j9m.convertedAmountUSDtoEUR2); + } +} From 6564693ea592bc3faff467a1158765499d20a6ac Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Mon, 27 Feb 2017 06:47:30 +0100 Subject: [PATCH 002/291] BAEL-41 - Renaming tests --- .../log4j2/tests/CustomLoggingTest.java | 34 ++++++++++++------- log4j2/src/test/resources/log4j2.xml | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/CustomLoggingTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/CustomLoggingTest.java index 1562b67068..333b4f5e78 100644 --- a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/CustomLoggingTest.java +++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/CustomLoggingTest.java @@ -31,78 +31,85 @@ public class CustomLoggingTest { } @Test - public void givenLoggerWithDefaultConfig_shouldLogToConsole() throws Exception { + public void givenLoggerWithDefaultConfig_whenLogToConsole_thanOK() throws Exception { Logger logger = LogManager.getLogger(getClass()); Exception e = new RuntimeException("This is only a test!"); + logger.info("This is a simple message at INFO level. " + "It will be hidden."); logger.error("This is a simple message at ERROR level. " + "This is the minimum visible level.", e); } @Test - public void givenLoggerWithConsoleConfig_shouldLogToConsoleInColors() throws Exception { + public void givenLoggerWithConsoleConfig_whenLogToConsoleInColors_thanOK() throws Exception { Logger logger = LogManager.getLogger("CONSOLE_PATTERN_APPENDER_MARKER"); + Exception e = new RuntimeException("This is only a test!"); + logger.trace("This is a colored message at TRACE level."); logger.debug("This is a colored message at DEBUG level. " + "This is the minimum visible level."); logger.info("This is a colored message at INFO level."); logger.warn("This is a colored message at WARN level."); - Exception e = new RuntimeException("This is only a test!"); logger.error("This is a colored message at ERROR level.", e); logger.fatal("This is a colored message at FATAL level."); } @Test - public void givenLoggerWithConsoleConfig_shouldFilterByMarker() throws Exception { + public void givenLoggerWithConsoleConfig_whenFilterByMarker_thanOK() throws Exception { Logger logger = LogManager.getLogger("CONSOLE_PATTERN_APPENDER_MARKER"); Marker appError = MarkerManager.getMarker("APP_ERROR"); - logger.error(appError, "This marker message at ERROR level should be hidden."); Marker connectionTrace = MarkerManager.getMarker("CONN_TRACE"); + + logger.error(appError, "This marker message at ERROR level should be hidden."); logger.trace(connectionTrace, "This is a marker message at TRACE level."); } @Test - public void givenLoggerWithConsoleConfig_shouldFilterByThreadContext() throws Exception { + public void givenLoggerWithConsoleConfig_whenFilterByThreadContext_thanOK() throws Exception { Logger logger = LogManager.getLogger("CONSOLE_PATTERN_APPENDER_THREAD_CONTEXT"); ThreadContext.put("userId", "1000"); logger.info("This is a log-visible user login. Maybe from an admin account?"); ThreadContext.put("userId", "1001"); logger.info("This is a log-invisible user login."); - } @Test - public void givenLoggerWithAsyncConfig_shouldLogToJsonFile() throws Exception { + public void givenLoggerWithAsyncConfig_whenLogToJsonFile_thanOK() throws Exception { Logger logger = LogManager.getLogger("ASYNC_JSON_FILE_APPENDER"); + final int count = 88; for (int i = 0; i < count; i++) { logger.info("This is async JSON message #{} at INFO level.", count); } + long logEventsCount = Files.lines(Paths.get("target/logfile.json")) .count(); assertTrue(logEventsCount > 0 && logEventsCount <= count); } @Test - public void givenLoggerWithFailoverConfig_shouldLog() throws Exception { + public void givenLoggerWithFailoverConfig_whenLog_thanOK() throws Exception { Logger logger = LogManager.getLogger("FAIL_OVER_SYSLOG_APPENDER"); + Exception e = new RuntimeException("This is only a test!"); + logger.trace("This is a syslog message at TRACE level."); logger.debug("This is a syslog message at DEBUG level."); logger.info("This is a syslog message at INFO level. This is the minimum visible level."); logger.warn("This is a syslog message at WARN level."); - Exception e = new RuntimeException("This is only a test!"); logger.error("This is a syslog message at ERROR level.", e); logger.fatal("This is a syslog message at FATAL level."); } @Test - public void givenLoggerWithJdbcConfig_shouldLogToDataSource() throws Exception { + public void givenLoggerWithJdbcConfig_whenLogToDataSource_thanOK() throws Exception { Logger logger = LogManager.getLogger("JDBC_APPENDER"); + final int count = 88; for (int i = 0; i < count; i++) { logger.info("This is JDBC message #{} at INFO level.", count); } Connection connection = ConnectionFactory.getConnection(); ResultSet resultSet = connection.createStatement() - .executeQuery("SELECT COUNT(*) AS ROW_COUNT FROM logs"); + .executeQuery("SELECT COUNT(*) AS ROW_COUNT FROM logs"); + int logCount = 0; if (resultSet.next()) { logCount = resultSet.getInt("ROW_COUNT"); @@ -111,8 +118,9 @@ public class CustomLoggingTest { } @Test - public void givenLoggerWithRollingFileConfig_shouldLogToXMLFile() throws Exception { + public void givenLoggerWithRollingFileConfig_whenLogToXMLFile_thanOK() throws Exception { Logger logger = LogManager.getLogger("XML_ROLLING_FILE_APPENDER"); + final int count = 88; for (int i = 0; i < count; i++) { logger.info("This is rolling file XML message #{} at INFO level.", i); diff --git a/log4j2/src/test/resources/log4j2.xml b/log4j2/src/test/resources/log4j2.xml index 83c1184f1f..b0640b16eb 100644 --- a/log4j2/src/test/resources/log4j2.xml +++ b/log4j2/src/test/resources/log4j2.xml @@ -19,7 +19,7 @@ - + From e6c1562f83427c857cb0e4136330de46edb41bd7 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Mon, 27 Feb 2017 07:10:30 +0100 Subject: [PATCH 003/291] BAEL-41 - Commenting out failover configuration --- log4j2/src/test/resources/log4j2.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/log4j2/src/test/resources/log4j2.xml b/log4j2/src/test/resources/log4j2.xml index b0640b16eb..21fd1da446 100644 --- a/log4j2/src/test/resources/log4j2.xml +++ b/log4j2/src/test/resources/log4j2.xml @@ -19,12 +19,14 @@ + @@ -53,9 +55,11 @@ + From d16ab250b16ad77e23cd9e85af36cb6e571d0e83 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Mon, 27 Feb 2017 18:31:59 +0100 Subject: [PATCH 004/291] Refactor SpringDataRelationshipsTest --- .../SpringDataRelationshipsTest.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java index ea2e70a4e4..21a067a645 100644 --- a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java @@ -1,5 +1,13 @@ package com.baeldung.relationships; +import com.baeldung.SpringDataRestApplication; +import com.baeldung.models.Address; +import com.baeldung.models.Author; +import com.baeldung.models.Book; +import com.baeldung.models.Library; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -11,17 +19,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.SpringDataRestApplication; -import com.baeldung.models.Address; -import com.baeldung.models.Author; -import com.baeldung.models.Book; -import com.baeldung.models.Library; - -import org.junit.Test; -import static org.junit.Assert.*; - -import org.json.JSONArray; -import org.json.JSONObject; +import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringDataRestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT) @@ -48,7 +46,7 @@ public class SpringDataRelationshipsTest { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("Content-type", "text/uri-list"); - HttpEntity httpEntity = new HttpEntity(ADDRESS_ENDPOINT + "/1", requestHeaders); + HttpEntity httpEntity = new HttpEntity<>(ADDRESS_ENDPOINT + "/1", requestHeaders); template.exchange(LIBRARY_ENDPOINT + "/1/libraryAddress", HttpMethod.PUT, httpEntity, String.class); ResponseEntity libraryGetResponse = template.getForEntity(ADDRESS_ENDPOINT + "/1/library", Library.class); @@ -69,7 +67,7 @@ public class SpringDataRelationshipsTest { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("Content-type", "text/uri-list"); - HttpEntity bookHttpEntity = new HttpEntity(LIBRARY_ENDPOINT + "/1", requestHeaders); + HttpEntity bookHttpEntity = new HttpEntity<>(LIBRARY_ENDPOINT + "/1", requestHeaders); template.exchange(BOOK_ENDPOINT + "/1/library", HttpMethod.PUT, bookHttpEntity, String.class); template.exchange(BOOK_ENDPOINT + "/2/library", HttpMethod.PUT, bookHttpEntity, String.class); @@ -91,7 +89,7 @@ public class SpringDataRelationshipsTest { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.add("Content-type", "text/uri-list"); - HttpEntity httpEntity = new HttpEntity(BOOK_ENDPOINT + "/1\n" + BOOK_ENDPOINT + "/2", requestHeaders); + HttpEntity httpEntity = new HttpEntity<>(BOOK_ENDPOINT + "/1\n" + BOOK_ENDPOINT + "/2", requestHeaders); template.exchange(AUTHOR_ENDPOINT + "/1/books", HttpMethod.PUT, httpEntity, String.class); String jsonResponse = template.getForObject(BOOK_ENDPOINT + "/1/authors", String.class); From a23eaf33235ee70476b8ea96c4b57028d2723615 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 27 Feb 2017 19:06:34 +0100 Subject: [PATCH 005/291] BAEL-311 add jasyp module --- jasypt/pom.xml | 34 +++++++++++++++++++ .../java/org/baeldung/jasypt/JasyptTest.java | 27 +++++++++++++++ pom.xml | 1 + 3 files changed, 62 insertions(+) create mode 100644 jasypt/pom.xml create mode 100644 jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java diff --git a/jasypt/pom.xml b/jasypt/pom.xml new file mode 100644 index 0000000000..7e0c51f0b9 --- /dev/null +++ b/jasypt/pom.xml @@ -0,0 +1,34 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + jasypt + + + + org.jasypt + jasypt + ${jasypt.version} + + + junit + junit + ${junit.version} + test + + + + + 1.9.2 + 4.12 + + + + \ No newline at end of file diff --git a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java new file mode 100644 index 0000000000..c81d605e50 --- /dev/null +++ b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java @@ -0,0 +1,27 @@ +package org.baeldung.jasypt; + + +import org.jasypt.util.text.BasicTextEncryptor; +import org.junit.Test; + +import static junit.framework.Assert.assertNotSame; +import static junit.framework.TestCase.assertEquals; + +public class JasyptTest { + + @Test + public void givenTextPassword_whenDecrypt_shouldCompareToEncrypted() { + //given + BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); + String password = "secret-pass"; + textEncryptor.setPasswordCharArray(password.toCharArray()); + + //when + String myEncryptedText = textEncryptor.encrypt("secret-pass"); + assertNotSame("secret-pass", myEncryptedText); //myEncryptedText can be save in db + + //then + String plainText = textEncryptor.decrypt(myEncryptedText); + assertEquals(plainText, "secret-pass"); + } +} diff --git a/pom.xml b/pom.xml index 014e4016c5..d42c184993 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,7 @@ javaslang javax-servlets javaxval + jasypt jaxb jee7 jjwt From 29fb2b339bdade9174c4b6bedd3427bb3369a888 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 27 Feb 2017 19:29:20 +0100 Subject: [PATCH 006/291] BAEL-311 two tests that works when installed legal_policy.jar --- .../java/org/baeldung/jasypt/JasyptTest.java | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java index c81d605e50..7d1265c887 100644 --- a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java +++ b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java @@ -1,7 +1,10 @@ package org.baeldung.jasypt; +import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.util.text.BasicTextEncryptor; +import org.junit.Ignore; import org.junit.Test; import static junit.framework.Assert.assertNotSame; @@ -17,11 +20,49 @@ public class JasyptTest { textEncryptor.setPasswordCharArray(password.toCharArray()); //when - String myEncryptedText = textEncryptor.encrypt("secret-pass"); - assertNotSame("secret-pass", myEncryptedText); //myEncryptedText can be save in db + String myEncryptedText = textEncryptor.encrypt(password); + assertNotSame(password, myEncryptedText); //myEncryptedText can be save in db //then String plainText = textEncryptor.decrypt(myEncryptedText); - assertEquals(plainText, "secret-pass"); + assertEquals(plainText, password); + } + + + @Test + @Ignore + public void givenTextPassword_whenDecrypt_shouldCompareToEncryptedWithCustomAlgorithm() { + //given + StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); + String password = "secret-pass"; + encryptor.setPassword("secret-pass"); + encryptor.setAlgorithm("PBEWithMD5AndTripleDES"); + + //when + String encryptedText = encryptor.encrypt("secret-pass"); + assertNotSame(password, encryptedText); + + //then + String plainText = encryptor.decrypt(encryptedText); + assertEquals(plainText, password); + } + + @Test + @Ignore + public void givenTextPassword_whenDecryptOnHighPerformance_shouldDecrypt(){ + //given + String password = "secret-pass"; + PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); + encryptor.setPoolSize(4); + encryptor.setPassword(password); + encryptor.setAlgorithm("PBEWithMD5AndTripleDES"); + + //when + String encryptedText = encryptor.encrypt(password); + assertNotSame(password, encryptedText); + + //then + String plainText = encryptor.decrypt(encryptedText); + assertEquals(plainText, password); } } From 64efdec3ef1669e3391a54e0520ccb92e1eeea2e Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 27 Feb 2017 19:31:19 +0100 Subject: [PATCH 007/291] BAEL-311 msg in ignore --- jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java index 7d1265c887..d05b18171d 100644 --- a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java +++ b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java @@ -30,7 +30,7 @@ public class JasyptTest { @Test - @Ignore + @Ignore("should have installed local_policy.jar") public void givenTextPassword_whenDecrypt_shouldCompareToEncryptedWithCustomAlgorithm() { //given StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); @@ -48,7 +48,7 @@ public class JasyptTest { } @Test - @Ignore + @Ignore("should have installed local_policy.jar") public void givenTextPassword_whenDecryptOnHighPerformance_shouldDecrypt(){ //given String password = "secret-pass"; From bb1b9c4ca43f5f3f2bb0acb2d7d28336de97f061 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 27 Feb 2017 15:13:19 -0400 Subject: [PATCH 008/291] Java Money & Currency --- .../.resourceCache/ECBCurrentRateProvider.dat | 60 +++--- .../ECBHistoric90RateProvider.dat | 10 +- .../IMFHistoricRateProvider.dat | 204 +++++++++--------- core-java/.resourceCache/IMFRateProvider.dat | 204 +++++++++--------- .../java/com/baeldung/money/JavaMoney.java | 8 +- .../com/baeldung/money/JavaMoneyTest.java | 37 ++-- 6 files changed, 269 insertions(+), 254 deletions(-) diff --git a/core-java/.resourceCache/ECBCurrentRateProvider.dat b/core-java/.resourceCache/ECBCurrentRateProvider.dat index 37d1d8c8ab..45cf516ac8 100644 --- a/core-java/.resourceCache/ECBCurrentRateProvider.dat +++ b/core-java/.resourceCache/ECBCurrentRateProvider.dat @@ -5,38 +5,38 @@ European Central Bank - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-java/.resourceCache/ECBHistoric90RateProvider.dat b/core-java/.resourceCache/ECBHistoric90RateProvider.dat index 16edc6a30a..f51c2eacfa 100644 --- a/core-java/.resourceCache/ECBHistoric90RateProvider.dat +++ b/core-java/.resourceCache/ECBHistoric90RateProvider.dat @@ -1,4 +1,7 @@ -Reference ratesEuropean Central Bank +Reference ratesEuropean Central Bank + + + @@ -57,7 +60,4 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/core-java/.resourceCache/IMFHistoricRateProvider.dat b/core-java/.resourceCache/IMFHistoricRateProvider.dat index 1db358b58b..4c98b3b04e 100644 --- a/core-java/.resourceCache/IMFHistoricRateProvider.dat +++ b/core-java/.resourceCache/IMFHistoricRateProvider.dat @@ -2,113 +2,113 @@ SDRs per Currency unit and Currency units per SDR (1) last five days SDRs per Currency unit (2) -Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 -Chinese Yuan 0.1077740000 0.1075920000 0.1074250000 0.1075990000 0.1078580000 -Euro 0.7806080000 0.7860480000 0.7864600000 0.7819020000 -Japanese Yen 0.0065267800 0.0065271000 0.0065062900 0.0064850300 0.0064793800 -U.K. Pound Sterling 0.9217470000 0.9201430000 0.9163910000 0.9224580000 0.9204290000 -U.S. Dollar 0.7413120000 0.7408260000 0.7380730000 0.7383210000 0.7407880000 -Algerian Dinar 0.0067122300 0.0067137500 0.0067192300 0.0067098500 -Australian Dollar 0.5680650000 0.5689800000 0.5694670000 0.5682580000 -Bahrain Dinar 1.9702800000 1.9629600000 1.9636200000 1.9701800000 -Botswana Pula 0.0708970000 0.0709288000 0.0712480000 0.0711156000 -Brazilian Real 0.2396560000 0.2419590000 0.2399250000 0.2389790000 -Brunei Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 -Canadian Dollar 0.5634090000 0.5627270000 0.5661790000 -Chilean Peso 0.0011535600 0.0011562200 0.0011537500 -Colombian Peso 0.0002552100 0.0002566600 0.0002567150 0.0002583270 -Czech Koruna 0.0288889000 0.0290901000 0.0291136000 -Danish Krone 0.1050150000 0.1057460000 0.1057900000 0.1051720000 -Hungarian Forint 0.0025387300 0.0025516800 0.0025498900 0.0025358200 -Icelandic Krona 0.0066885700 0.0066860500 0.0066725800 0.0066218600 -Indian Rupee 0.0110083000 0.0110285000 0.0110699000 -Indonesian Rupiah 0.0000554096 0.0000553776 0.0000553921 -Iranian Rial 0.0000228671 0.0000227947 0.0000228695 -Israeli New Sheqel 0.1998450000 0.1986200000 0.1986870000 0.1977020000 -Kazakhstani Tenge 0.0023350800 0.0023165400 0.0023114400 0.0023099100 -Korean Won 0.0006455440 0.0006480580 0.0006467420 0.0006472590 -Kuwaiti Dinar 2.4257600000 2.4171400000 2.4179500000 2.4248400000 +Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 +Chinese Yuan 0.1075530000 0.1074200000 0.1076250000 0.1077740000 0.1075920000 +Euro 0.7826360000 0.7829640000 0.7824120000 0.7793410000 0.7806080000 +Japanese Yen 0.0065915500 0.0065398200 0.0065279600 0.0065267800 0.0065271000 +U.K. Pound Sterling 0.9178430000 0.9263250000 0.9233090000 0.9217470000 0.9201430000 +U.S. Dollar 0.7392420000 0.7380190000 0.7400090000 0.7413120000 0.7408260000 +Algerian Dinar 0.0067056800 0.0067170500 0.0067108200 0.0067122300 +Australian Dollar 0.5695290000 0.5688450000 0.5701430000 0.5680650000 +Bahrain Dinar 1.9628200000 1.9681100000 1.9715700000 1.9702800000 +Botswana Pula 0.0712926000 0.0714849000 0.0710918000 0.0708970000 +Brazilian Real 0.2409310000 0.2401220000 0.2394110000 0.2396560000 +Brunei Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 +Canadian Dollar 0.5632010000 0.5645050000 0.5621540000 0.5634090000 +Chilean Peso 0.0011525100 0.0011535400 0.0011517700 0.0011535600 +Colombian Peso 0.0002570000 0.0002557440 0.0002553890 0.0002552100 +Czech Koruna 0.0289783000 0.0289564000 0.0288448000 0.0288889000 +Danish Krone 0.1053170000 0.1052550000 0.1048460000 0.1050150000 +Hungarian Forint 0.0025337100 0.0025343600 0.0025357900 0.0025387300 +Icelandic Krona 0.0068082900 0.0067593100 0.0067227000 0.0066885700 +Indian Rupee 0.0110722000 0.0110702000 +Indonesian Rupiah 0.0000553404 0.0000553899 0.0000555040 0.0000554096 +Iranian Rial 0.0000228786 0.0000228671 +Israeli New Sheqel 0.1995720000 0.1995710000 0.1998150000 0.1998450000 +Kazakhstani Tenge 0.0023693200 0.0023668900 0.0023601900 0.0023350800 +Korean Won 0.0006480670 0.0006486190 0.0006464180 0.0006455440 +Kuwaiti Dinar 2.4165700000 2.4230800000 2.4273500000 2.4257600000 Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1661230000 0.1655610000 0.1656540000 0.1664690000 -Mauritian Rupee 0.0207521000 0.0207775000 0.0208634000 -Mexican Peso 0.0360870000 0.0364464000 -Nepalese Rupee 0.0069139200 0.0068914400 0.0068937500 0.0069148500 -New Zealand Dollar 0.5306540000 0.5322980000 0.5342490000 0.5300340000 -Norwegian Krone 0.0885668000 0.0886734000 0.0886755000 0.0883278000 -Rial Omani 1.9267300000 1.9195700000 1.9202100000 1.9266300000 -Pakistani Rupee 0.0070658600 0.0070405000 0.0070429300 0.0070671000 -Nuevo Sol 0.2264720000 -Philippine Peso 0.0147628000 0.0147836000 0.0148472000 -Polish Zloty 0.1809450000 0.1813760000 0.1820000000 0.1817800000 -Qatar Riyal 0.2035240000 0.2027670000 0.2028350000 0.2035130000 -Russian Ruble 0.0128040000 0.0128062000 0.0129188000 0.0130485000 -Saudi Arabian Riyal 0.1975540000 0.1968190000 0.1968860000 0.1975430000 -Singapore Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 -South African Rand 0.0562263000 0.0562860000 0.0569367000 0.0568608000 -Sri Lanka Rupee 0.0049020900 0.0048960700 0.0048979200 0.0049141600 -Swedish Krona 0.0824973000 0.0830639000 0.0829146000 0.0828400000 -Swiss Franc 0.7337090000 0.7385900000 0.7376570000 0.7341080000 -Thai Baht 0.0211393000 0.0210914000 0.0210961000 0.0211545000 -Trinidad And Tobago Dollar 0.1095510000 0.1093120000 0.1094000000 0.1097660000 -Tunisian Dinar 0.3234230000 0.3229230000 0.3212750000 0.3239130000 -U.A.E. Dirham 0.2017230000 0.2009730000 0.2010400000 0.2017120000 -Peso Uruguayo 0.0260937000 0.0260969000 -Bolivar Fuerte 0.0740171000 0.0742645000 +Malaysian Ringgit 0.1659960000 0.1662940000 0.1663250000 0.1661230000 +Mauritian Rupee 0.0208418000 +Mexican Peso 0.0372107000 0.0375618000 0.0372281000 0.0362282000 +Nepalese Rupee 0.0069012400 0.0069030700 0.0069229700 0.0069139200 +New Zealand Dollar 0.5331450000 0.5322880000 0.5307790000 0.5306540000 +Norwegian Krone 0.0886062000 0.0888398000 0.0884082000 0.0885668000 +Rial Omani 1.9194300000 1.9246000000 1.9279900000 1.9267300000 +Pakistani Rupee 0.0070384300 0.0070575400 0.0070700400 0.0070658600 +Nuevo Sol 0.2283980000 0.2287290000 0.2281570000 +Philippine Peso 0.0146922000 0.0147295000 0.0147363000 0.0147628000 +Polish Zloty 0.1814160000 0.1811970000 0.1812540000 0.1809450000 +Qatar Riyal 0.2027520000 0.2032990000 0.2036570000 0.2035240000 +Russian Ruble 0.0128977000 0.0128040000 +Saudi Arabian Riyal 0.1968050000 0.1973360000 0.1976830000 0.1975540000 +Singapore Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 +South African Rand 0.0569347000 0.0570889000 0.0566127000 0.0562263000 +Sri Lanka Rupee 0.0048931100 0.0049014800 0.0049020900 +Swedish Krona 0.0822544000 0.0824642000 0.0823543000 0.0824973000 +Swiss Franc 0.7345670000 0.7331180000 0.7312210000 0.7337090000 +Thai Baht 0.0211098000 0.0211467000 0.0211707000 0.0211393000 +Trinidad And Tobago Dollar 0.1092030000 0.1091300000 0.1093820000 0.1095510000 +Tunisian Dinar 0.3206630000 0.3204540000 0.3225790000 0.3234230000 +U.A.E. Dirham 0.2009580000 0.2015000000 0.2018550000 0.2017230000 +Peso Uruguayo 0.0259816000 0.0261108000 0.0261517000 +Bolivar Fuerte 0.0739869000 0.0741864000 Currency units per SDR(3) -Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 -Chinese Yuan 9.278680 9.294370 9.308820 9.293770 9.271450 -Euro 1.281050 1.272190 1.271520 1.278930 -Japanese Yen 153.215000 153.207000 153.697000 154.201000 154.336000 -U.K. Pound Sterling 1.084900 1.086790 1.091240 1.084060 1.086450 -U.S. Dollar 1.348960 1.349840 1.354880 1.354420 1.349910 -Algerian Dinar 148.982000 148.948000 148.827000 149.035000 -Australian Dollar 1.760360 1.757530 1.756030 1.759760 -Bahrain Dinar 0.507542 0.509435 0.509264 0.507568 -Botswana Pula 14.105000 14.098600 14.035500 14.061600 -Brazilian Real 4.172650 4.132930 4.167970 4.184470 -Brunei Dollar 1.917730 1.920410 1.922470 1.915930 -Canadian Dollar 1.774910 1.777060 1.766230 -Chilean Peso 866.882000 864.887000 866.739000 -Colombian Peso 3,918.340000 3,896.210000 3,895.370000 3,871.060000 -Czech Koruna 34.615400 34.376000 34.348200 -Danish Krone 9.522450 9.456620 9.452690 9.508230 -Hungarian Forint 393.898000 391.899000 392.174000 394.350000 -Icelandic Krona 149.509000 149.565000 149.867000 151.015000 -Indian Rupee 90.840500 90.674200 90.335100 -Indonesian Rupiah 18,047.400000 18,057.800000 18,053.100000 -Iranian Rial 43,730.900000 43,869.800000 43,726.400000 -Israeli New Sheqel 5.003880 5.034740 5.033040 5.058120 -Kazakhstani Tenge 428.251000 431.678000 432.631000 432.917000 -Korean Won 1,549.080000 1,543.070000 1,546.210000 1,544.980000 -Kuwaiti Dinar 0.412242 0.413712 0.413573 0.412398 +Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 +Chinese Yuan 9.297740 9.309250 9.291520 9.278680 9.294370 +Euro 1.277730 1.277200 1.278100 1.283140 1.281050 +Japanese Yen 151.709000 152.909000 153.187000 153.215000 153.207000 +U.K. Pound Sterling 1.089510 1.079530 1.083060 1.084900 1.086790 +U.S. Dollar 1.352740 1.354980 1.351330 1.348960 1.349840 +Algerian Dinar 149.127000 148.875000 149.013000 148.982000 +Australian Dollar 1.755840 1.757950 1.753950 1.760360 +Bahrain Dinar 0.509471 0.508102 0.507210 0.507542 +Botswana Pula 14.026700 13.989000 14.066300 14.105000 +Brazilian Real 4.150570 4.164550 4.176920 4.172650 +Brunei Dollar 1.903340 1.911870 1.913900 1.917730 +Canadian Dollar 1.775570 1.771460 1.778870 1.774910 +Chilean Peso 867.671000 866.897000 868.229000 866.882000 +Colombian Peso 3,891.050000 3,910.160000 3,915.600000 3,918.340000 +Czech Koruna 34.508600 34.534700 34.668300 34.615400 +Danish Krone 9.495140 9.500740 9.537800 9.522450 +Hungarian Forint 394.678000 394.577000 394.354000 393.898000 +Icelandic Krona 146.880000 147.944000 148.750000 149.509000 +Indian Rupee 90.316300 90.332600 +Indonesian Rupiah 18,070.000000 18,053.800000 18,016.700000 18,047.400000 +Iranian Rial 43,709.000000 43,730.900000 +Israeli New Sheqel 5.010720 5.010750 5.004630 5.003880 +Kazakhstani Tenge 422.062000 422.495000 423.695000 428.251000 +Korean Won 1,543.050000 1,541.740000 1,546.990000 1,549.080000 +Kuwaiti Dinar 0.413810 0.412698 0.411972 0.412242 Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 6.019640 6.040070 6.036680 6.007120 -Mauritian Rupee 48.187900 48.129000 47.930800 -Mexican Peso 27.710800 27.437600 -Nepalese Rupee 144.636000 145.108000 145.059000 144.616000 -New Zealand Dollar 1.884470 1.878650 1.871790 1.886670 -Norwegian Krone 11.290900 11.277300 11.277100 11.321500 -Rial Omani 0.519014 0.520950 0.520776 0.519041 -Pakistani Rupee 141.526000 142.035000 141.986000 141.501000 -Nuevo Sol 4.415560 -Philippine Peso 67.737800 67.642500 67.352800 -Polish Zloty 5.526540 5.513410 5.494510 5.501160 -Qatar Riyal 4.913430 4.931770 4.930120 4.913690 -Russian Ruble 78.100600 78.087200 77.406600 76.637200 -Saudi Arabian Riyal 5.061910 5.080810 5.079080 5.062190 -Singapore Dollar 1.917730 1.920410 1.922470 1.915930 -South African Rand 17.785300 17.766400 17.563400 17.586800 -Sri Lanka Rupee 203.995000 204.245000 204.168000 203.494000 -Swedish Krona 12.121600 12.038900 12.060600 12.071500 -Swiss Franc 1.362940 1.353930 1.355640 1.362200 -Thai Baht 47.305300 47.412700 47.402100 47.271300 -Trinidad And Tobago Dollar 9.128170 9.148130 9.140770 9.110290 -Tunisian Dinar 3.091930 3.096710 3.112600 3.087250 -U.A.E. Dirham 4.957290 4.975790 4.974130 4.957560 -Peso Uruguayo 38.323400 38.318700 -Bolivar Fuerte 13.510400 13.465400 +Malaysian Ringgit 6.024240 6.013450 6.012330 6.019640 +Mauritian Rupee 47.980500 +Mexican Peso 26.874000 26.622800 26.861400 27.602800 +Nepalese Rupee 144.901000 144.863000 144.447000 144.636000 +New Zealand Dollar 1.875660 1.878680 1.884020 1.884470 +Norwegian Krone 11.285900 11.256200 11.311200 11.290900 +Rial Omani 0.520988 0.519588 0.518675 0.519014 +Pakistani Rupee 142.077000 141.692000 141.442000 141.526000 +Nuevo Sol 4.378320 4.371990 4.382950 +Philippine Peso 68.063300 67.891000 67.859600 67.737800 +Polish Zloty 5.512190 5.518860 5.517120 5.526540 +Qatar Riyal 4.932130 4.918860 4.910220 4.913430 +Russian Ruble 77.533200 78.100600 +Saudi Arabian Riyal 5.081170 5.067500 5.058600 5.061910 +Singapore Dollar 1.903340 1.911870 1.913900 1.917730 +South African Rand 17.564000 17.516500 17.663900 17.785300 +Sri Lanka Rupee 204.369000 204.020000 203.995000 +Swedish Krona 12.157400 12.126500 12.142700 12.121600 +Swiss Franc 1.361350 1.364040 1.367580 1.362940 +Thai Baht 47.371400 47.288700 47.235100 47.305300 +Trinidad And Tobago Dollar 9.157260 9.163380 9.142270 9.128170 +Tunisian Dinar 3.118540 3.120570 3.100020 3.091930 +U.A.E. Dirham 4.976160 4.962780 4.954050 4.957290 +Peso Uruguayo 38.488800 38.298300 38.238400 +Bolivar Fuerte 13.515900 13.479600 (1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. diff --git a/core-java/.resourceCache/IMFRateProvider.dat b/core-java/.resourceCache/IMFRateProvider.dat index 1db358b58b..4c98b3b04e 100644 --- a/core-java/.resourceCache/IMFRateProvider.dat +++ b/core-java/.resourceCache/IMFRateProvider.dat @@ -2,113 +2,113 @@ SDRs per Currency unit and Currency units per SDR (1) last five days SDRs per Currency unit (2) -Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 -Chinese Yuan 0.1077740000 0.1075920000 0.1074250000 0.1075990000 0.1078580000 -Euro 0.7806080000 0.7860480000 0.7864600000 0.7819020000 -Japanese Yen 0.0065267800 0.0065271000 0.0065062900 0.0064850300 0.0064793800 -U.K. Pound Sterling 0.9217470000 0.9201430000 0.9163910000 0.9224580000 0.9204290000 -U.S. Dollar 0.7413120000 0.7408260000 0.7380730000 0.7383210000 0.7407880000 -Algerian Dinar 0.0067122300 0.0067137500 0.0067192300 0.0067098500 -Australian Dollar 0.5680650000 0.5689800000 0.5694670000 0.5682580000 -Bahrain Dinar 1.9702800000 1.9629600000 1.9636200000 1.9701800000 -Botswana Pula 0.0708970000 0.0709288000 0.0712480000 0.0711156000 -Brazilian Real 0.2396560000 0.2419590000 0.2399250000 0.2389790000 -Brunei Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 -Canadian Dollar 0.5634090000 0.5627270000 0.5661790000 -Chilean Peso 0.0011535600 0.0011562200 0.0011537500 -Colombian Peso 0.0002552100 0.0002566600 0.0002567150 0.0002583270 -Czech Koruna 0.0288889000 0.0290901000 0.0291136000 -Danish Krone 0.1050150000 0.1057460000 0.1057900000 0.1051720000 -Hungarian Forint 0.0025387300 0.0025516800 0.0025498900 0.0025358200 -Icelandic Krona 0.0066885700 0.0066860500 0.0066725800 0.0066218600 -Indian Rupee 0.0110083000 0.0110285000 0.0110699000 -Indonesian Rupiah 0.0000554096 0.0000553776 0.0000553921 -Iranian Rial 0.0000228671 0.0000227947 0.0000228695 -Israeli New Sheqel 0.1998450000 0.1986200000 0.1986870000 0.1977020000 -Kazakhstani Tenge 0.0023350800 0.0023165400 0.0023114400 0.0023099100 -Korean Won 0.0006455440 0.0006480580 0.0006467420 0.0006472590 -Kuwaiti Dinar 2.4257600000 2.4171400000 2.4179500000 2.4248400000 +Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 +Chinese Yuan 0.1075530000 0.1074200000 0.1076250000 0.1077740000 0.1075920000 +Euro 0.7826360000 0.7829640000 0.7824120000 0.7793410000 0.7806080000 +Japanese Yen 0.0065915500 0.0065398200 0.0065279600 0.0065267800 0.0065271000 +U.K. Pound Sterling 0.9178430000 0.9263250000 0.9233090000 0.9217470000 0.9201430000 +U.S. Dollar 0.7392420000 0.7380190000 0.7400090000 0.7413120000 0.7408260000 +Algerian Dinar 0.0067056800 0.0067170500 0.0067108200 0.0067122300 +Australian Dollar 0.5695290000 0.5688450000 0.5701430000 0.5680650000 +Bahrain Dinar 1.9628200000 1.9681100000 1.9715700000 1.9702800000 +Botswana Pula 0.0712926000 0.0714849000 0.0710918000 0.0708970000 +Brazilian Real 0.2409310000 0.2401220000 0.2394110000 0.2396560000 +Brunei Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 +Canadian Dollar 0.5632010000 0.5645050000 0.5621540000 0.5634090000 +Chilean Peso 0.0011525100 0.0011535400 0.0011517700 0.0011535600 +Colombian Peso 0.0002570000 0.0002557440 0.0002553890 0.0002552100 +Czech Koruna 0.0289783000 0.0289564000 0.0288448000 0.0288889000 +Danish Krone 0.1053170000 0.1052550000 0.1048460000 0.1050150000 +Hungarian Forint 0.0025337100 0.0025343600 0.0025357900 0.0025387300 +Icelandic Krona 0.0068082900 0.0067593100 0.0067227000 0.0066885700 +Indian Rupee 0.0110722000 0.0110702000 +Indonesian Rupiah 0.0000553404 0.0000553899 0.0000555040 0.0000554096 +Iranian Rial 0.0000228786 0.0000228671 +Israeli New Sheqel 0.1995720000 0.1995710000 0.1998150000 0.1998450000 +Kazakhstani Tenge 0.0023693200 0.0023668900 0.0023601900 0.0023350800 +Korean Won 0.0006480670 0.0006486190 0.0006464180 0.0006455440 +Kuwaiti Dinar 2.4165700000 2.4230800000 2.4273500000 2.4257600000 Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1661230000 0.1655610000 0.1656540000 0.1664690000 -Mauritian Rupee 0.0207521000 0.0207775000 0.0208634000 -Mexican Peso 0.0360870000 0.0364464000 -Nepalese Rupee 0.0069139200 0.0068914400 0.0068937500 0.0069148500 -New Zealand Dollar 0.5306540000 0.5322980000 0.5342490000 0.5300340000 -Norwegian Krone 0.0885668000 0.0886734000 0.0886755000 0.0883278000 -Rial Omani 1.9267300000 1.9195700000 1.9202100000 1.9266300000 -Pakistani Rupee 0.0070658600 0.0070405000 0.0070429300 0.0070671000 -Nuevo Sol 0.2264720000 -Philippine Peso 0.0147628000 0.0147836000 0.0148472000 -Polish Zloty 0.1809450000 0.1813760000 0.1820000000 0.1817800000 -Qatar Riyal 0.2035240000 0.2027670000 0.2028350000 0.2035130000 -Russian Ruble 0.0128040000 0.0128062000 0.0129188000 0.0130485000 -Saudi Arabian Riyal 0.1975540000 0.1968190000 0.1968860000 0.1975430000 -Singapore Dollar 0.5214510000 0.5207230000 0.5201640000 0.5219390000 -South African Rand 0.0562263000 0.0562860000 0.0569367000 0.0568608000 -Sri Lanka Rupee 0.0049020900 0.0048960700 0.0048979200 0.0049141600 -Swedish Krona 0.0824973000 0.0830639000 0.0829146000 0.0828400000 -Swiss Franc 0.7337090000 0.7385900000 0.7376570000 0.7341080000 -Thai Baht 0.0211393000 0.0210914000 0.0210961000 0.0211545000 -Trinidad And Tobago Dollar 0.1095510000 0.1093120000 0.1094000000 0.1097660000 -Tunisian Dinar 0.3234230000 0.3229230000 0.3212750000 0.3239130000 -U.A.E. Dirham 0.2017230000 0.2009730000 0.2010400000 0.2017120000 -Peso Uruguayo 0.0260937000 0.0260969000 -Bolivar Fuerte 0.0740171000 0.0742645000 +Malaysian Ringgit 0.1659960000 0.1662940000 0.1663250000 0.1661230000 +Mauritian Rupee 0.0208418000 +Mexican Peso 0.0372107000 0.0375618000 0.0372281000 0.0362282000 +Nepalese Rupee 0.0069012400 0.0069030700 0.0069229700 0.0069139200 +New Zealand Dollar 0.5331450000 0.5322880000 0.5307790000 0.5306540000 +Norwegian Krone 0.0886062000 0.0888398000 0.0884082000 0.0885668000 +Rial Omani 1.9194300000 1.9246000000 1.9279900000 1.9267300000 +Pakistani Rupee 0.0070384300 0.0070575400 0.0070700400 0.0070658600 +Nuevo Sol 0.2283980000 0.2287290000 0.2281570000 +Philippine Peso 0.0146922000 0.0147295000 0.0147363000 0.0147628000 +Polish Zloty 0.1814160000 0.1811970000 0.1812540000 0.1809450000 +Qatar Riyal 0.2027520000 0.2032990000 0.2036570000 0.2035240000 +Russian Ruble 0.0128977000 0.0128040000 +Saudi Arabian Riyal 0.1968050000 0.1973360000 0.1976830000 0.1975540000 +Singapore Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 +South African Rand 0.0569347000 0.0570889000 0.0566127000 0.0562263000 +Sri Lanka Rupee 0.0048931100 0.0049014800 0.0049020900 +Swedish Krona 0.0822544000 0.0824642000 0.0823543000 0.0824973000 +Swiss Franc 0.7345670000 0.7331180000 0.7312210000 0.7337090000 +Thai Baht 0.0211098000 0.0211467000 0.0211707000 0.0211393000 +Trinidad And Tobago Dollar 0.1092030000 0.1091300000 0.1093820000 0.1095510000 +Tunisian Dinar 0.3206630000 0.3204540000 0.3225790000 0.3234230000 +U.A.E. Dirham 0.2009580000 0.2015000000 0.2018550000 0.2017230000 +Peso Uruguayo 0.0259816000 0.0261108000 0.0261517000 +Bolivar Fuerte 0.0739869000 0.0741864000 Currency units per SDR(3) -Currency February 22, 2017 February 21, 2017 February 17, 2017 February 16, 2017 February 15, 2017 -Chinese Yuan 9.278680 9.294370 9.308820 9.293770 9.271450 -Euro 1.281050 1.272190 1.271520 1.278930 -Japanese Yen 153.215000 153.207000 153.697000 154.201000 154.336000 -U.K. Pound Sterling 1.084900 1.086790 1.091240 1.084060 1.086450 -U.S. Dollar 1.348960 1.349840 1.354880 1.354420 1.349910 -Algerian Dinar 148.982000 148.948000 148.827000 149.035000 -Australian Dollar 1.760360 1.757530 1.756030 1.759760 -Bahrain Dinar 0.507542 0.509435 0.509264 0.507568 -Botswana Pula 14.105000 14.098600 14.035500 14.061600 -Brazilian Real 4.172650 4.132930 4.167970 4.184470 -Brunei Dollar 1.917730 1.920410 1.922470 1.915930 -Canadian Dollar 1.774910 1.777060 1.766230 -Chilean Peso 866.882000 864.887000 866.739000 -Colombian Peso 3,918.340000 3,896.210000 3,895.370000 3,871.060000 -Czech Koruna 34.615400 34.376000 34.348200 -Danish Krone 9.522450 9.456620 9.452690 9.508230 -Hungarian Forint 393.898000 391.899000 392.174000 394.350000 -Icelandic Krona 149.509000 149.565000 149.867000 151.015000 -Indian Rupee 90.840500 90.674200 90.335100 -Indonesian Rupiah 18,047.400000 18,057.800000 18,053.100000 -Iranian Rial 43,730.900000 43,869.800000 43,726.400000 -Israeli New Sheqel 5.003880 5.034740 5.033040 5.058120 -Kazakhstani Tenge 428.251000 431.678000 432.631000 432.917000 -Korean Won 1,549.080000 1,543.070000 1,546.210000 1,544.980000 -Kuwaiti Dinar 0.412242 0.413712 0.413573 0.412398 +Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 +Chinese Yuan 9.297740 9.309250 9.291520 9.278680 9.294370 +Euro 1.277730 1.277200 1.278100 1.283140 1.281050 +Japanese Yen 151.709000 152.909000 153.187000 153.215000 153.207000 +U.K. Pound Sterling 1.089510 1.079530 1.083060 1.084900 1.086790 +U.S. Dollar 1.352740 1.354980 1.351330 1.348960 1.349840 +Algerian Dinar 149.127000 148.875000 149.013000 148.982000 +Australian Dollar 1.755840 1.757950 1.753950 1.760360 +Bahrain Dinar 0.509471 0.508102 0.507210 0.507542 +Botswana Pula 14.026700 13.989000 14.066300 14.105000 +Brazilian Real 4.150570 4.164550 4.176920 4.172650 +Brunei Dollar 1.903340 1.911870 1.913900 1.917730 +Canadian Dollar 1.775570 1.771460 1.778870 1.774910 +Chilean Peso 867.671000 866.897000 868.229000 866.882000 +Colombian Peso 3,891.050000 3,910.160000 3,915.600000 3,918.340000 +Czech Koruna 34.508600 34.534700 34.668300 34.615400 +Danish Krone 9.495140 9.500740 9.537800 9.522450 +Hungarian Forint 394.678000 394.577000 394.354000 393.898000 +Icelandic Krona 146.880000 147.944000 148.750000 149.509000 +Indian Rupee 90.316300 90.332600 +Indonesian Rupiah 18,070.000000 18,053.800000 18,016.700000 18,047.400000 +Iranian Rial 43,709.000000 43,730.900000 +Israeli New Sheqel 5.010720 5.010750 5.004630 5.003880 +Kazakhstani Tenge 422.062000 422.495000 423.695000 428.251000 +Korean Won 1,543.050000 1,541.740000 1,546.990000 1,549.080000 +Kuwaiti Dinar 0.413810 0.412698 0.411972 0.412242 Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 6.019640 6.040070 6.036680 6.007120 -Mauritian Rupee 48.187900 48.129000 47.930800 -Mexican Peso 27.710800 27.437600 -Nepalese Rupee 144.636000 145.108000 145.059000 144.616000 -New Zealand Dollar 1.884470 1.878650 1.871790 1.886670 -Norwegian Krone 11.290900 11.277300 11.277100 11.321500 -Rial Omani 0.519014 0.520950 0.520776 0.519041 -Pakistani Rupee 141.526000 142.035000 141.986000 141.501000 -Nuevo Sol 4.415560 -Philippine Peso 67.737800 67.642500 67.352800 -Polish Zloty 5.526540 5.513410 5.494510 5.501160 -Qatar Riyal 4.913430 4.931770 4.930120 4.913690 -Russian Ruble 78.100600 78.087200 77.406600 76.637200 -Saudi Arabian Riyal 5.061910 5.080810 5.079080 5.062190 -Singapore Dollar 1.917730 1.920410 1.922470 1.915930 -South African Rand 17.785300 17.766400 17.563400 17.586800 -Sri Lanka Rupee 203.995000 204.245000 204.168000 203.494000 -Swedish Krona 12.121600 12.038900 12.060600 12.071500 -Swiss Franc 1.362940 1.353930 1.355640 1.362200 -Thai Baht 47.305300 47.412700 47.402100 47.271300 -Trinidad And Tobago Dollar 9.128170 9.148130 9.140770 9.110290 -Tunisian Dinar 3.091930 3.096710 3.112600 3.087250 -U.A.E. Dirham 4.957290 4.975790 4.974130 4.957560 -Peso Uruguayo 38.323400 38.318700 -Bolivar Fuerte 13.510400 13.465400 +Malaysian Ringgit 6.024240 6.013450 6.012330 6.019640 +Mauritian Rupee 47.980500 +Mexican Peso 26.874000 26.622800 26.861400 27.602800 +Nepalese Rupee 144.901000 144.863000 144.447000 144.636000 +New Zealand Dollar 1.875660 1.878680 1.884020 1.884470 +Norwegian Krone 11.285900 11.256200 11.311200 11.290900 +Rial Omani 0.520988 0.519588 0.518675 0.519014 +Pakistani Rupee 142.077000 141.692000 141.442000 141.526000 +Nuevo Sol 4.378320 4.371990 4.382950 +Philippine Peso 68.063300 67.891000 67.859600 67.737800 +Polish Zloty 5.512190 5.518860 5.517120 5.526540 +Qatar Riyal 4.932130 4.918860 4.910220 4.913430 +Russian Ruble 77.533200 78.100600 +Saudi Arabian Riyal 5.081170 5.067500 5.058600 5.061910 +Singapore Dollar 1.903340 1.911870 1.913900 1.917730 +South African Rand 17.564000 17.516500 17.663900 17.785300 +Sri Lanka Rupee 204.369000 204.020000 203.995000 +Swedish Krona 12.157400 12.126500 12.142700 12.121600 +Swiss Franc 1.361350 1.364040 1.367580 1.362940 +Thai Baht 47.371400 47.288700 47.235100 47.305300 +Trinidad And Tobago Dollar 9.157260 9.163380 9.142270 9.128170 +Tunisian Dinar 3.118540 3.120570 3.100020 3.091930 +U.A.E. Dirham 4.976160 4.962780 4.954050 4.957290 +Peso Uruguayo 38.488800 38.298300 38.238400 +Bolivar Fuerte 13.515900 13.479600 (1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. diff --git a/core-java/src/main/java/com/baeldung/money/JavaMoney.java b/core-java/src/main/java/com/baeldung/money/JavaMoney.java index f66480bea5..3171d226ed 100644 --- a/core-java/src/main/java/com/baeldung/money/JavaMoney.java +++ b/core-java/src/main/java/com/baeldung/money/JavaMoney.java @@ -81,7 +81,11 @@ public class JavaMoney { LOGGER.info("Money & FastMoney operations : " + calcMoneyFastMoney); - monetaryAmounts = new MonetaryAmount[] { Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF"), }; + monetaryAmounts = + new MonetaryAmount[] { + Money.of(100, "CHF"), + Money.of(10.20, "CHF"), + Money.of(1.15, "CHF"), }; sumAmtCHF = Money.of(0, "CHF"); for (MonetaryAmount monetaryAmount : monetaryAmounts) { sumAmtCHF = sumAmtCHF.add(monetaryAmount); @@ -134,7 +138,7 @@ public class JavaMoney { usFormatted = formatUSD.format(oneDolar); LOGGER.info("One dolar standard formatted : " + usFormatted); - customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern", "00000.00 ¤").build()); + customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern", "00000.00 ¤").build()); customFormatted = customFormat.format(oneDolar); LOGGER.info("One dolar custom formatted : " + customFormatted); } diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index 25fcd48f7a..5aa12095ff 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -1,24 +1,24 @@ package com.baeldung.money; +import static org.junit.Assert.*; + import javax.money.convert.ConversionQueryBuilder; import javax.money.convert.MonetaryConversions; +import org.junit.Test; + import com.baeldung.money.JavaMoney; import junit.framework.TestCase; public class JavaMoneyTest - extends TestCase { - JavaMoney j9m; - public JavaMoneyTest( String testName ) - { - super( testName ); - j9m = new JavaMoney(); - } - public void testAmounts() + @Test + public void givenAmountsAreCorrect() { + JavaMoney j9m; + j9m = new JavaMoney(); assertEquals("USD", j9m.USD.toString()); assertEquals("USD 1", j9m.oneDolar.toString()); assertEquals("EUR 1", j9m.oneEuro.toString()); @@ -29,7 +29,10 @@ public class JavaMoneyTest } - public void testArithmetic(){ + @Test + public void givenArithmeticIsCorrect(){ + JavaMoney j9m; + j9m = new JavaMoney(); assertEquals("USD -199.5", j9m.calcAmtUSD.toString()); assertEquals("CHF 111.35", j9m.sumAmtCHF.toString()); assertEquals("USD 10", j9m.calcMoneyFastMoney.toString()); @@ -37,17 +40,25 @@ public class JavaMoneyTest assertEquals("USD 4", j9m.divideAmount.toString()); } - public void testRounding(){ + @Test + public void givenRoundingIsCorrect(){ + JavaMoney j9m; + j9m = new JavaMoney(); assertEquals("EUR 1.3", j9m.roundEUR.toString()); } - public void testFormatting(){ + @Test + public void givenFormatIsCorrect(){ + JavaMoney j9m; + j9m = new JavaMoney(); assertEquals("USD1.00", j9m.usFormatted); assertEquals("00001.00 US Dollar", j9m.customFormatted); } - public void testConversion(){ - + @Test + public void givenConversionIsNotNull(){ + JavaMoney j9m; + j9m = new JavaMoney(); assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build())); assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("USD").build())); assertNotNull(j9m.convertedAmountEURtoUSD); From 1bfc944c5a5db228a6bd648794360df6aeb58225 Mon Sep 17 00:00:00 2001 From: Nancy Bosecker Date: Mon, 27 Feb 2017 20:26:30 -0800 Subject: [PATCH 009/291] Added more indexing/delete/query examples to code (#1251) * Solr w Apache SolrJ * Solr w Apache SolrJ * updated test names and moved add to @before method * create apache-solrj module, moved code from spring-data-solr * More examples for indexing,delete,and query for solrj * More examples for indexing,delete,and query for solrj --- .../com/baeldung/solrjava/ProductBean.java | 44 +++++++++++++ .../solrjava/SolrJavaIntegration.java | 15 ++++- .../solrjava/SolrJavaIntegrationTest.java | 62 +++++++++++++++++-- 3 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java diff --git a/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java b/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java new file mode 100644 index 0000000000..14eea8f2f9 --- /dev/null +++ b/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java @@ -0,0 +1,44 @@ +package com.baeldung.solrjava; + +import org.apache.solr.client.solrj.beans.Field; + +public class ProductBean { + + String id; + String name; + String price; + + public ProductBean(String id, String name, String price) { + super(); + this.id = id; + this.name = name; + this.price = price; + } + + public String getId() { + return id; + } + + @Field("id") + protected void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + @Field("name") + protected void setName(String name) { + this.name = name; + } + + public String getPrice() { + return price; + } + + @Field("price") + protected void setPrice(String price) { + this.price = price; + } +} diff --git a/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java b/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java index f2d21f0993..c55e1c9ada 100644 --- a/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java +++ b/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java @@ -17,6 +17,12 @@ public class SolrJavaIntegration { solrClient.setParser(new XMLResponseParser()); } + public void addProductBean(ProductBean pBean) throws IOException, SolrServerException { + + solrClient.addBean(pBean); + solrClient.commit(); + } + public void addSolrDocument(String documentId, String itemName, String itemPrice) throws SolrServerException, IOException { SolrInputDocument document = new SolrInputDocument(); @@ -27,12 +33,18 @@ public class SolrJavaIntegration { solrClient.commit(); } - public void deleteSolrDocument(String documentId) throws SolrServerException, IOException { + public void deleteSolrDocumentById(String documentId) throws SolrServerException, IOException { solrClient.deleteById(documentId); solrClient.commit(); } + public void deleteSolrDocumentByQuery(String query) throws SolrServerException, IOException { + + solrClient.deleteByQuery(query); + solrClient.commit(); + } + protected HttpSolrClient getSolrClient() { return solrClient; } @@ -40,4 +52,5 @@ public class SolrJavaIntegration { protected void setSolrClient(HttpSolrClient solrClient) { this.solrClient = solrClient; } + } diff --git a/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java index 22f9eae8ee..7f4599a91d 100644 --- a/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java +++ b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java @@ -24,7 +24,7 @@ public class SolrJavaIntegrationTest { } @Test - public void whenAdd_thenVerifyAdded() throws SolrServerException, IOException { + public void whenAdd_thenVerifyAddedByQueryOnId() throws SolrServerException, IOException { SolrQuery query = new SolrQuery(); query.set("q", "id:123456"); @@ -36,15 +36,65 @@ public class SolrJavaIntegrationTest { assertEquals(docList.getNumFound(), 1); for (SolrDocument doc : docList) { - assertEquals((String) doc.getFieldValue("id"), "123456"); - assertEquals((Double) doc.getFieldValue("price"), (Double) 599.99); + assertEquals("Kenmore Dishwasher", (String) doc.getFieldValue("name")); + assertEquals((Double) 599.99, (Double) doc.getFieldValue("price")); } } @Test - public void whenDelete_thenVerifyDeleted() throws SolrServerException, IOException { + public void whenAdd_thenVerifyAddedByQueryOnPrice() throws SolrServerException, IOException { - solrJavaIntegration.deleteSolrDocument("123456"); + SolrQuery query = new SolrQuery(); + query.set("q", "price:599.99"); + QueryResponse response = null; + + response = solrJavaIntegration.getSolrClient().query(query); + + SolrDocumentList docList = response.getResults(); + assertEquals(1, docList.getNumFound()); + + for (SolrDocument doc : docList) { + assertEquals("123456", (String) doc.getFieldValue("id")); + assertEquals((Double) 599.99, (Double) doc.getFieldValue("price")); + } + } + + @Test + public void whenAdd_thenVerifyAddedByQuery() throws SolrServerException, IOException { + + SolrDocument doc = solrJavaIntegration.getSolrClient().getById("123456"); + assertEquals("Kenmore Dishwasher", (String) doc.getFieldValue("name")); + assertEquals((Double) 599.99, (Double) doc.getFieldValue("price")); + } + + @Test + public void whenAddBean_thenVerifyAddedByQuery() throws SolrServerException, IOException { + + ProductBean pBean = new ProductBean("888", "Apple iPhone 6s", "299.99"); + solrJavaIntegration.addProductBean(pBean); + + SolrDocument doc = solrJavaIntegration.getSolrClient().getById("888"); + assertEquals("Apple iPhone 6s", (String) doc.getFieldValue("name")); + assertEquals((Double) 299.99, (Double) doc.getFieldValue("price")); + } + + @Test + public void whenDeleteById_thenVerifyDeleted() throws SolrServerException, IOException { + + solrJavaIntegration.deleteSolrDocumentById("123456"); + + SolrQuery query = new SolrQuery(); + query.set("q", "id:123456"); + QueryResponse response = solrJavaIntegration.getSolrClient().query(query); + + SolrDocumentList docList = response.getResults(); + assertEquals(0, docList.getNumFound()); + } + + @Test + public void whenDeleteByQuery_thenVerifyDeleted() throws SolrServerException, IOException { + + solrJavaIntegration.deleteSolrDocumentByQuery("name:Kenmore Dishwasher"); SolrQuery query = new SolrQuery(); query.set("q", "id:123456"); @@ -53,6 +103,6 @@ public class SolrJavaIntegrationTest { response = solrJavaIntegration.getSolrClient().query(query); SolrDocumentList docList = response.getResults(); - assertEquals(docList.getNumFound(), 0); + assertEquals(0, docList.getNumFound()); } } From 442c00545c4fe7109c971d2dd6414dc619df301e Mon Sep 17 00:00:00 2001 From: mujahid Date: Wed, 1 Mar 2017 02:00:13 +0800 Subject: [PATCH 010/291] BAEL-347-Full-text search with SOLR (#1254) * solr-fulltext-search module created * solr-fulltext-search modue created * solr-fulltext-search change s * pom changes merged from upstream --- solr-fulltext-search/pom.xml | 2 +- .../solr/fulltext/search/model/Item.java | 51 +++ .../search/service/ItemSearchService.java | 15 + .../search/service/ItemSearchServiceImpl.java | 34 ++ .../ItemSearchServiceIntegrationTest.java | 374 ++++++++++++++++++ 5 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java create mode 100644 solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java create mode 100644 solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java create mode 100644 solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java diff --git a/solr-fulltext-search/pom.xml b/solr-fulltext-search/pom.xml index 4afcb5838a..bed6afd48f 100644 --- a/solr-fulltext-search/pom.xml +++ b/solr-fulltext-search/pom.xml @@ -18,7 +18,7 @@ org.apache.solr solr-solrj - 6.1.0 + 6.4.1 log4j diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java new file mode 100644 index 0000000000..d7a0524ca9 --- /dev/null +++ b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java @@ -0,0 +1,51 @@ +package com.baeldung.solr.fulltext.search.model; + +import org.apache.solr.client.solrj.beans.Field; + +public class Item { + + @Field + private String id; + + @Field + private String description; + + @Field + private String category; + + @Field + private float price; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public float getPrice() { + return price; + } + + public void setPrice(float price) { + this.price = price; + } + +} diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java new file mode 100644 index 0000000000..fa906fc975 --- /dev/null +++ b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java @@ -0,0 +1,15 @@ +package com.baeldung.solr.fulltext.search.service; + +import java.io.IOException; + +import org.apache.solr.client.solrj.SolrServerException; + +import com.baeldung.solr.fulltext.search.model.Item; + +public interface ItemSearchService { + + public void index(String id, String description, String category, float price) throws SolrServerException, IOException; + + public void indexBean(Item item) throws IOException, SolrServerException; + +} diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java new file mode 100644 index 0000000000..573cc58bc0 --- /dev/null +++ b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java @@ -0,0 +1,34 @@ +package com.baeldung.solr.fulltext.search.service; + +import java.io.IOException; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.common.SolrInputDocument; + +import com.baeldung.solr.fulltext.search.model.Item; + +public class ItemSearchServiceImpl implements ItemSearchService { + + private final SolrClient solrClient; + + public ItemSearchServiceImpl(SolrClient solrClient) { + this.solrClient = solrClient; + } + + public void index(String id, String description, String category, float price) throws SolrServerException, IOException { + SolrInputDocument doc = new SolrInputDocument(); + doc.addField("id", id); + doc.addField("description", description); + doc.addField("category", category); + doc.addField("price", price); + solrClient.add(doc); + solrClient.commit(); + } + + public void indexBean(Item item) throws IOException, SolrServerException { + solrClient.addBean(item); + solrClient.commit(); + } + +} diff --git a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java b/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java new file mode 100644 index 0000000000..94661ffc2e --- /dev/null +++ b/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java @@ -0,0 +1,374 @@ +package com.baeldung.solr.fulltext.search.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.response.FacetField.Count; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.response.RangeFacet; +import org.apache.solr.client.solrj.response.SpellCheckResponse; +import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; +import org.apache.solr.client.solrj.response.SuggesterResponse; +import org.apache.solr.common.SolrDocument; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.baeldung.solr.fulltext.search.model.Item; + +public class ItemSearchServiceIntegrationTest { + + private static SolrClient solrClient; + private static ItemSearchService itemSearchService; + private static final String solrUrl = "http://localhost:8987/solr/item"; + + @BeforeClass + public static void initBeans() throws Exception { + solrClient = new HttpSolrClient.Builder(solrUrl).build(); + itemSearchService = new ItemSearchServiceImpl(solrClient); + + solrClient.commit(); + } + + @Before + public void clearSolrData() throws Exception { + solrClient.deleteByQuery("*:*"); + } + + @Test + public void whenIndexing_thenAvailableOnRetrieval() throws Exception { + itemSearchService.index("hm0001", "Washing Machine", "Home Appliances", 450f); + final SolrDocument indexedDoc = solrClient.getById("hm0001"); + assertEquals("hm0001", indexedDoc.get("id")); + } + + @Test + public void whenIndexingBean_thenAvailableOnRetrieval() throws Exception { + Item item = new Item(); + item.setId("hm0002"); + item.setCategory("Televisions"); + item.setDescription("LED TV 32"); + item.setPrice(500); + itemSearchService.indexBean(item); + } + + @Test + public void whenSearchingByBasicQuery_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("brand1"); + query.setStart(0); + query.setRows(10); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + + } + + @Test + public void whenSearchingWithWildCard_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*rand?"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + } + + @Test + public void whenSearchingWithLogicalOperators_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 LED TV 32", "Washing Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("brand1 AND (Washing OR Refrigerator)"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFields_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("0003", "Brand2 LED TV 32", "Brand1 Washing Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("description:Brand* AND category:*Washing*"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingWithPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("washing MachIne"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithRealPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("\"washing machine\""); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingPhraseWithProximity_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("\"Washing equipment\"~2"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingWithPriceRange_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:[100 TO 300]"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + } + + @Test + public void whenSearchingWithPriceRangeInclusiveExclusive_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:{100 TO 300]"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFilterQuery_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:[100 TO 300]"); + query.addFilterQuery("description:Brand1", "category:Home Appliances"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFacetFields_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + query.addFacetField("category"); + + QueryResponse response = solrClient.query(query); + List facetResults = response.getFacetField("category").getValues(); + + assertEquals(2, facetResults.size()); + + for (Count count : facetResults) { + if ("categorya".equalsIgnoreCase(count.getName())) { + assertEquals(2, count.getCount()); + } else if ("categoryb".equalsIgnoreCase(count.getName())) { + assertEquals(2, count.getCount()); + } else { + fail("unexpected category"); + } + } + } + + @Test + public void whenSearchingWithFacetQuery_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + + query.addFacetQuery("Washing OR Refrigerator"); + query.addFacetQuery("Brand2"); + + QueryResponse response = solrClient.query(query); + Map facetQueryMap = response.getFacetQuery(); + + assertEquals(2, facetQueryMap.size()); + + for (Map.Entry entry : facetQueryMap.entrySet()) { + String facetQuery = entry.getKey(); + + if ("Washing OR Refrigerator".equals(facetQuery)) { + assertEquals(Integer.valueOf(2), entry.getValue()); + } else if ("Brand2".equals(facetQuery)) { + assertEquals(Integer.valueOf(2), entry.getValue()); + } else { + fail("unexpected query"); + } + + } + } + + @Test + public void whenSearchingWithFacetRange_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 125f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 150f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + + query.addNumericRangeFacet("price", 100, 275, 25); + + QueryResponse response = solrClient.query(query); + List rangeFacets = response.getFacetRanges().get(0).getCounts(); + + assertEquals(7, rangeFacets.size()); + } + + @Test + public void whenSearchingWithHitHighlighting_thenKeywordsShouldBeHighlighted() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("Appliances"); + query.setHighlight(true); + query.addHighlightField("category"); + query.setHighlightSimplePre(""); + query.setHighlightSimplePost(""); + QueryResponse response = solrClient.query(query); + + Map>> hitHighlightedMap = response.getHighlighting(); + Map> highlightedFieldMap = hitHighlightedMap.get("hm0001"); + List highlightedList = highlightedFieldMap.get("category"); + String highLightedText = highlightedList.get(0); + + assertEquals("Home Appliances", highLightedText); + + } + + @Test + public void whenSearchingWithKeywordWithMistake_thenSpellingSuggestionsShouldBeReturned() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("hme"); + query.set("spellcheck", "on"); + QueryResponse response = solrClient.query(query); + + SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse(); + + assertEquals(false, spellCheckResponse.isCorrectlySpelled()); + + Suggestion suggestion = spellCheckResponse.getSuggestions().get(0); + + assertEquals("hme", suggestion.getToken()); + + List alternatives = suggestion.getAlternatives(); + String alternative = alternatives.get(0); + + assertEquals("home", alternative); + } + + @Test + public void whenSearchingWithIncompleteKeyword_thenKeywordSuggestionsShouldBeReturned() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Home washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setRequestHandler("/suggest"); + query.set("suggest", "true"); + query.set("suggest.build", "true"); + query.set("suggest.dictionary", "mySuggester"); + query.set("suggest.q", "Hom"); + QueryResponse response = solrClient.query(query); + + SuggesterResponse suggesterResponse = response.getSuggesterResponse(); + Map> suggestedTerms = suggesterResponse.getSuggestedTerms(); + List suggestions = suggestedTerms.get("mySuggester"); + + assertEquals(2, suggestions.size()); + + for (String term : suggestions) { + if (!"Home Appliances".equals(term) && !"Home washing equipments".equals(term)) { + fail("Unexpected suggestions"); + } + } + + } + +} From d1f0b2e554ce5d8b3a30d35aa0f5b89edd96c80a Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Wed, 1 Mar 2017 16:47:07 +0530 Subject: [PATCH 011/291] BAEL-701 Introduction to TestNG --- testng/pom.xml | 234 +++++++++--------- .../java/baeldung/com/DependentTests.java | 50 ++-- .../java/baeldung/com/MultiThreadedTests.java | 14 ++ .../java/baeldung/com/ParametrizedTests.java | 154 ++++++------ .../java/baeldung/com/RegistrationTest.java | 28 +-- .../test/java/baeldung/com/SignInTest.java | 28 +-- .../baeldung/com/SummationServiceTest.java | 196 +++++++-------- .../src/test/java/baeldung/com/TestGroup.java | 86 +++---- .../test/java/baeldung/com/TimeOutTest.java | 22 +- .../baeldung/reports/CustomisedListener.java | 67 +++++ .../baeldung/reports/CustomisedReports.java | 50 ++++ testng/src/test/resources/logback.xml | 26 +- ...rized_test.xml => parametrized_testng.xml} | 21 +- testng/src/test/resources/test_group.xml | 24 +- testng/src/test/resources/test_setup.xml | 32 +-- testng/src/test/resources/test_suite.xml | 19 +- 16 files changed, 597 insertions(+), 454 deletions(-) create mode 100644 testng/src/test/java/baeldung/com/MultiThreadedTests.java create mode 100644 testng/src/test/java/com/baeldung/reports/CustomisedListener.java create mode 100644 testng/src/test/java/com/baeldung/reports/CustomisedReports.java rename testng/src/test/resources/{parametrized_test.xml => parametrized_testng.xml} (74%) diff --git a/testng/pom.xml b/testng/pom.xml index 272b1d316d..5cf8ab06f3 100644 --- a/testng/pom.xml +++ b/testng/pom.xml @@ -1,115 +1,121 @@ - - - 4.0.0 - com.baeldung - testng - 0.1.0-SNAPSHOT - jar - testng - - - - - - - org.slf4j - slf4j-api - ${org.slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - - - org.testng - testng - ${testng.version} - test - - - - - - testng - - - src/main/resources - true - - - - - src/main/resources - true - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - **/*IntegrationTest.java - **/*LongRunningUnitTest.java - **/*ManualTest.java - - true - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - - - - - - - - - - - - 1.7.21 - 1.1.7 - - - 6.10 - - - 3.6.0 - 2.19.1 - - - - + + + 4.0.0 + com.baeldung + testng + 0.1.0-SNAPSHOT + jar + testng + + + + + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + + org.testng + testng + ${testng.version} + test + + + + + + testng + + + src/main/resources + true + + + + + src/main/resources + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + + + src\test\resources\parametrized_testng.xml + src\test\resources\test_group.xml + src\test\resources\test_setup.xml + src\test\resources\test_suite.xml + + + true + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/libs + + + + + + + + + + + + 1.7.21 + 1.1.7 + + + 6.10 + + + 3.6.0 + 2.19.1 + + + + \ No newline at end of file diff --git a/testng/src/test/java/baeldung/com/DependentTests.java b/testng/src/test/java/baeldung/com/DependentTests.java index b60f8a6c0d..8d3bbfc11b 100644 --- a/testng/src/test/java/baeldung/com/DependentTests.java +++ b/testng/src/test/java/baeldung/com/DependentTests.java @@ -1,25 +1,25 @@ -package baeldung.com; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; - -public class DependentTests { - - private static final Logger LOGGER = LoggerFactory.getLogger(DependentTests.class); - - private String email = "abc@qwe.com"; - - @Test - public void givenEmail_ifValid_thenTrue() { - boolean valid = email.contains("@"); - Assert.assertEquals(valid, true); - } - - @Test(dependsOnMethods = {"givenEmail_ifValid_thenTrue"}) - public void givenValidEmail_whenLoggedIn_thenTrue() { - LOGGER.info("Email {} valid >> logging in", email); - } -} - +package baeldung.com; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class DependentTests { + + private static final Logger LOGGER = LoggerFactory.getLogger(DependentTests.class); + + private String email = "abc@qwe.com"; + + @Test + public void givenEmail_ifValid_thenTrue() { + boolean valid = email.contains("@"); + Assert.assertEquals(valid, true); + } + + @Test(dependsOnMethods = {"givenEmail_ifValid_thenTrue"}) + public void givenValidEmail_whenLoggedIn_thenTrue() { + LOGGER.info("Email {} valid >> logging in", email); + } +} + diff --git a/testng/src/test/java/baeldung/com/MultiThreadedTests.java b/testng/src/test/java/baeldung/com/MultiThreadedTests.java new file mode 100644 index 0000000000..48096b8c20 --- /dev/null +++ b/testng/src/test/java/baeldung/com/MultiThreadedTests.java @@ -0,0 +1,14 @@ +package baeldung.com; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class MultiThreadedTests { + + @Test(threadPoolSize = 5, invocationCount = 10, timeOut = 1000) + public void givenMethod_whenRunInThreads_thenCorrect(){ + int count = Thread.activeCount(); + Assert.assertTrue(count>1); + } + +} diff --git a/testng/src/test/java/baeldung/com/ParametrizedTests.java b/testng/src/test/java/baeldung/com/ParametrizedTests.java index d3813f5382..693a1b5cde 100644 --- a/testng/src/test/java/baeldung/com/ParametrizedTests.java +++ b/testng/src/test/java/baeldung/com/ParametrizedTests.java @@ -1,77 +1,77 @@ -package baeldung.com; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Parameters; -import org.testng.annotations.Test; - -public class ParametrizedTests { - - private static final Logger LOGGER = LoggerFactory.getLogger(ParametrizedTests.class); - - @Test - @Parameters({"value", "isEven"}) - public void givenNumberFromXML_ifEvenCheckOK_thenCorrect(int value, boolean isEven) { - Assert.assertEquals(isEven, value % 2 == 0); - } - - @DataProvider(name = "numbers") - public static Object[][] evenNumbers() { - return new Object[][]{{1, false}, {2, true}, {4, true}}; - } - - @Test(dataProvider = "numbers") - public void givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect(Integer number, boolean expected) { - Assert.assertEquals(expected, number % 2 == 0); - } - - @Test(dataProvider = "numbersObject") - public void givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect(EvenNumber number) { - Assert.assertEquals(number.isEven(), number.getValue() % 2 == 0); - } - - @DataProvider(name = "numbersObject") - public Object[][] parameterProvider() { - return new Object[][]{{new EvenNumber(1, false)}, {new EvenNumber(2, true)}, {new EvenNumber(4, true),}}; - } - -} - - -class EvenNumber { - private int value; - private boolean isEven; - - public EvenNumber(int number, boolean isEven) { - this.value = number; - this.isEven = isEven; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - - public boolean isEven() { - return isEven; - } - - public void setEven(boolean even) { - isEven = even; - } - - @Override - public String toString() { - return "EvenNumber{" + - "value=" + value + - ", isEven=" + isEven + - '}'; - } -} - - +package baeldung.com; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Parameters; +import org.testng.annotations.Test; + +public class ParametrizedTests { + + private static final Logger LOGGER = LoggerFactory.getLogger(ParametrizedTests.class); + + @Test + @Parameters({"value", "isEven"}) + public void givenNumberFromXML_ifEvenCheckOK_thenCorrect(int value, boolean isEven) { + Assert.assertEquals(isEven, value % 2 == 0); + } + + @DataProvider(name = "numbers") + public static Object[][] evenNumbers() { + return new Object[][]{{1, false}, {2, true}, {4, true}}; + } + + @Test(dataProvider = "numbers") + public void givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect(Integer number, boolean expected) { + Assert.assertEquals(expected, number % 2 == 0); + } + + @Test(dataProvider = "numbersObject") + public void givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect(EvenNumber number) { + Assert.assertEquals(number.isEven(), number.getValue() % 2 == 0); + } + + @DataProvider(name = "numbersObject") + public Object[][] parameterProvider() { + return new Object[][]{{new EvenNumber(1, false)}, {new EvenNumber(2, true)}, {new EvenNumber(4, true),}}; + } + +} + + +class EvenNumber { + private int value; + private boolean isEven; + + public EvenNumber(int number, boolean isEven) { + this.value = number; + this.isEven = isEven; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public boolean isEven() { + return isEven; + } + + public void setEven(boolean even) { + isEven = even; + } + + @Override + public String toString() { + return "EvenNumber{" + + "value=" + value + + ", isEven=" + isEven + + '}'; + } +} + + diff --git a/testng/src/test/java/baeldung/com/RegistrationTest.java b/testng/src/test/java/baeldung/com/RegistrationTest.java index ec551d9c27..e9d744902b 100644 --- a/testng/src/test/java/baeldung/com/RegistrationTest.java +++ b/testng/src/test/java/baeldung/com/RegistrationTest.java @@ -1,14 +1,14 @@ -package baeldung.com; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.Test; - -public class RegistrationTest { - private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationTest.class); - - @Test - public void whenCalledFromSuite_thanOK() { - LOGGER.info("Registration successful"); - } -} +package baeldung.com; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +public class RegistrationTest { + private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationTest.class); + + @Test + public void whenCalledFromSuite_thanOK() { + LOGGER.info("Registration successful"); + } +} diff --git a/testng/src/test/java/baeldung/com/SignInTest.java b/testng/src/test/java/baeldung/com/SignInTest.java index f0547374d1..d5cad78de0 100644 --- a/testng/src/test/java/baeldung/com/SignInTest.java +++ b/testng/src/test/java/baeldung/com/SignInTest.java @@ -1,14 +1,14 @@ -package baeldung.com; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.Test; - -public class SignInTest { - private static final Logger LOGGER = LoggerFactory.getLogger(SignInTest.class); - - @Test - public void whenCalledFromSuite_thanOK() { - LOGGER.info("SignIn successful"); - } -} +package baeldung.com; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +public class SignInTest { + private static final Logger LOGGER = LoggerFactory.getLogger(SignInTest.class); + + @Test + public void whenCalledFromSuite_thanOK() { + LOGGER.info("SignIn successful"); + } +} diff --git a/testng/src/test/java/baeldung/com/SummationServiceTest.java b/testng/src/test/java/baeldung/com/SummationServiceTest.java index f377a009df..ceed53ca42 100644 --- a/testng/src/test/java/baeldung/com/SummationServiceTest.java +++ b/testng/src/test/java/baeldung/com/SummationServiceTest.java @@ -1,98 +1,98 @@ -package baeldung.com; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.TestNG; -import org.testng.annotations.*; - -import java.util.ArrayList; -import java.util.List; - -public class SummationServiceTest extends TestNG { - private static final Logger LOGGER = LoggerFactory.getLogger(DependentTests.class); - - private List numbers; - - private int testCount = 0; - - @BeforeClass - public void initialize() { - numbers = new ArrayList<>(); - } - - @AfterClass - public void tearDown() { - numbers = null; - } - - @BeforeSuite(groups = "regression") - public void runBeforeRegressionSuite() { - numbers = new ArrayList<>(); - numbers.add(-11); - numbers.add(2); - } - - @AfterSuite(groups = "regression") - public void runAfterRegressionSuite() { - numbers = null; - } - - @BeforeGroups("negative_tests") - public void runBeforeEachNegativeGroup() { - numbers.clear(); - } - - @BeforeGroups("regression") - public void runBeforeEachRegressionGroup() { - numbers.add(-11); - numbers.add(2); - } - - @BeforeGroups("positive_tests") - public void runBeforeEachPositiveGroup() { - numbers.add(1); - numbers.add(2); - numbers.add(3); - } - - @AfterGroups("positive_tests,regression,negative_tests") - public void runAfterEachGroup() { - numbers.clear(); - } - - @BeforeMethod - public void runBeforeEachTest() { - testCount++; - } - - @AfterMethod - public void runAfterEachTest() { - - } - - - @Test(groups = "positive_tests", enabled = false) - public void givenNumbers_sumEquals_thenCorrect() { - int sum = numbers.stream().reduce(0, Integer::sum); - Assert.assertEquals(sum, 6); - } - - @Test(groups = "negative_tests") - public void givenEmptyList_sumEqualsZero_thenCorrect() { - int sum = numbers.stream().reduce(0, Integer::sum); - Assert.assertEquals(0, sum); - } - - @Test(groups = "regression") - public void givenNegativeNumber_sumLessthanZero_thenCorrect() { - int sum = numbers.stream().reduce(0, Integer::sum); - Assert.assertTrue(sum < 0); - } - - @Test(expectedExceptions = ArithmeticException.class) - public void givenNumber_whenThrowsException_thenCorrect() { - int i = 1 / 0; - } - -} +package baeldung.com; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.TestNG; +import org.testng.annotations.*; + +import java.util.ArrayList; +import java.util.List; + +public class SummationServiceTest extends TestNG { + private static final Logger LOGGER = LoggerFactory.getLogger(DependentTests.class); + + private List numbers; + + private int testCount = 0; + + @BeforeClass + public void initialize() { + numbers = new ArrayList<>(); + } + + @AfterClass + public void tearDown() { + numbers = null; + } + + @BeforeSuite(groups = "regression") + public void runBeforeRegressionSuite() { + numbers = new ArrayList<>(); + numbers.add(-11); + numbers.add(2); + } + + @AfterSuite(groups = "regression") + public void runAfterRegressionSuite() { + numbers = null; + } + + @BeforeGroups("negative_tests") + public void runBeforeEachNegativeGroup() { + numbers.clear(); + } + + @BeforeGroups("regression") + public void runBeforeEachRegressionGroup() { + numbers.add(-11); + numbers.add(2); + } + + @BeforeGroups("positive_tests") + public void runBeforeEachPositiveGroup() { + numbers.add(1); + numbers.add(2); + numbers.add(3); + } + + @AfterGroups("positive_tests,regression,negative_tests") + public void runAfterEachGroup() { + numbers.clear(); + } + + @BeforeMethod + public void runBeforeEachTest() { + testCount++; + } + + @AfterMethod + public void runAfterEachTest() { + + } + + + @Test(groups = "positive_tests", enabled = false) + public void givenNumbers_sumEquals_thenCorrect() { + int sum = numbers.stream().reduce(0, Integer::sum); + Assert.assertEquals(sum, 6); + } + + @Test(groups = "negative_tests") + public void givenEmptyList_sumEqualsZero_thenCorrect() { + int sum = numbers.stream().reduce(0, Integer::sum); + Assert.assertEquals(0, sum); + } + + @Test(groups = "regression") + public void givenNegativeNumber_sumLessthanZero_thenCorrect() { + int sum = numbers.stream().reduce(0, Integer::sum); + Assert.assertTrue(sum < 0); + } + + @Test(expectedExceptions = ArithmeticException.class) + public void givenNumber_whenThrowsException_thenCorrect() { + int i = 1 / 0; + } + +} diff --git a/testng/src/test/java/baeldung/com/TestGroup.java b/testng/src/test/java/baeldung/com/TestGroup.java index 08bb5c996e..014fad7f8b 100644 --- a/testng/src/test/java/baeldung/com/TestGroup.java +++ b/testng/src/test/java/baeldung/com/TestGroup.java @@ -1,44 +1,44 @@ -package baeldung.com; - -import org.testng.annotations.AfterGroups; -import org.testng.annotations.BeforeGroups; -import org.testng.annotations.Test; - -public class TestGroup { - - @BeforeGroups("database") - public void setupDB() { - System.out.println("setupDB()"); - } - - @AfterGroups("database") - public void cleanDB() { - System.out.println("cleanDB()"); - } - - @Test(groups= "selenium-test") - public void runSelenium() { - System.out.println("runSelenium()"); - } - - @Test(groups= "selenium-test") - public void runSelenium1() { - System.out.println("runSelenium()1"); - } - - @Test(groups = "database") - public void testConnectOracle() { - System.out.println("testConnectOracle()"); - } - - @Test(groups = "database") - public void testConnectMsSQL() { - System.out.println("testConnectMsSQL"); - } - - @Test(dependsOnGroups = {"database","selenium-test"}) - public void runFinal() { - System.out.println("runFinal"); - } - +package baeldung.com; + +import org.testng.annotations.AfterGroups; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +public class TestGroup { + + @BeforeGroups("database") + public void setupDB() { + System.out.println("setupDB()"); + } + + @AfterGroups("database") + public void cleanDB() { + System.out.println("cleanDB()"); + } + + @Test(groups= "selenium-test") + public void runSelenium() { + System.out.println("runSelenium()"); + } + + @Test(groups= "selenium-test") + public void runSelenium1() { + System.out.println("runSelenium()1"); + } + + @Test(groups = "database") + public void testConnectOracle() { + System.out.println("testConnectOracle()"); + } + + @Test(groups = "database") + public void testConnectMsSQL() { + System.out.println("testConnectMsSQL"); + } + + @Test(dependsOnGroups = {"database","selenium-test"}) + public void runFinal() { + System.out.println("runFinal"); + } + } \ No newline at end of file diff --git a/testng/src/test/java/baeldung/com/TimeOutTest.java b/testng/src/test/java/baeldung/com/TimeOutTest.java index d54a914e08..f84367a972 100644 --- a/testng/src/test/java/baeldung/com/TimeOutTest.java +++ b/testng/src/test/java/baeldung/com/TimeOutTest.java @@ -1,11 +1,11 @@ -package baeldung.com; - -import org.testng.annotations.Test; - -public class TimeOutTest { - - @Test(timeOut = 1000, enabled = false) - public void givenExecution_takeMoreTime_thenFail() { - while (true) ; - } -} +package baeldung.com; + +import org.testng.annotations.Test; + +public class TimeOutTest { + + @Test(timeOut = 1000, enabled = false) + public void givenExecution_takeMoreTime_thenFail() { + while (true) ; + } +} diff --git a/testng/src/test/java/com/baeldung/reports/CustomisedListener.java b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java new file mode 100644 index 0000000000..179ca5f736 --- /dev/null +++ b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java @@ -0,0 +1,67 @@ +package com.baeldung.reports; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; + +public class CustomisedListener implements ITestListener { + private static final Logger LOGGER = LoggerFactory.getLogger("TEST_REPORT"); + + @Override + public void onFinish(ITestContext arg0) { + LOGGER.info("PASSED TEST CASES"); + arg0.getPassedTests() + .getAllResults() + .stream() + .forEach(result -> { + LOGGER.info(result.getName()); + }); + LOGGER.info("FAILED TEST CASES"); + arg0.getFailedTests() + .getAllResults() + .stream() + .forEach(result -> { + LOGGER.info(result.getName()); + }); + LOGGER.info("Test completed on: "+arg0.getEndDate().toString()); + } + + @Override + public void onStart(ITestContext arg0) { + LOGGER.info("Started testing on: " + arg0.getStartDate() + .toString()); + } + + @Override + public void onTestFailedButWithinSuccessPercentage(ITestResult arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onTestFailure(ITestResult arg0) { + LOGGER.info("Failed : " + arg0.getName()); + + } + + @Override + public void onTestSkipped(ITestResult arg0) { + LOGGER.info("Skipped Test: " + arg0.getName()); + + } + + @Override + public void onTestStart(ITestResult arg0) { + LOGGER.info("Testing: " + arg0.getName() + " " + arg0.getStartMillis()); + + } + + @Override + public void onTestSuccess(ITestResult arg0) { + LOGGER.info("Tested: " + arg0.getName() + " " + arg0.getEndMillis()); + + } + +} diff --git a/testng/src/test/java/com/baeldung/reports/CustomisedReports.java b/testng/src/test/java/com/baeldung/reports/CustomisedReports.java new file mode 100644 index 0000000000..e59ecbd79b --- /dev/null +++ b/testng/src/test/java/com/baeldung/reports/CustomisedReports.java @@ -0,0 +1,50 @@ +package com.baeldung.reports; + +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.IReporter; +import org.testng.ISuite; +import org.testng.ISuiteResult; +import org.testng.ITestContext; +import org.testng.xml.XmlSuite; + +public class CustomisedReports implements IReporter { + private static final Logger LOGGER = LoggerFactory.getLogger("TEST_REPORT"); + + @Override + public void generateReport(List xmlSuites, List suites, String outputDirectory) { + + suites.stream() + .forEach(suite -> { + String suiteName = suite.getName(); + Map suiteResults = suite.getResults(); + suiteResults.values() + .stream() + .forEach(result -> { + ITestContext context + = ((ISuiteResult) result).getTestContext(); + + LOGGER.info("Passed tests for suite '" + + suiteName + "' is:" + + context.getPassedTests() + .getAllResults() + .size()); + LOGGER.info("Failed tests for suite '" + + suiteName + "' is:" + + context.getFailedTests() + .getAllResults() + .size()); + LOGGER.info("Skipped tests for suite '" + + suiteName + "' is:" + + context.getSkippedTests() + .getAllResults() + .size()); + }); + }); + + } + +} diff --git a/testng/src/test/resources/logback.xml b/testng/src/test/resources/logback.xml index e9ae1894a6..346682f033 100644 --- a/testng/src/test/resources/logback.xml +++ b/testng/src/test/resources/logback.xml @@ -1,14 +1,14 @@ - - - - - web - %date [%thread] %-5level %logger{36} - %message%n - - - - - - - - + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + \ No newline at end of file diff --git a/testng/src/test/resources/parametrized_test.xml b/testng/src/test/resources/parametrized_testng.xml similarity index 74% rename from testng/src/test/resources/parametrized_test.xml rename to testng/src/test/resources/parametrized_testng.xml index 932af30e4e..c8ec7209f8 100644 --- a/testng/src/test/resources/parametrized_test.xml +++ b/testng/src/test/resources/parametrized_testng.xml @@ -1,10 +1,13 @@ - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/testng/src/test/resources/test_group.xml b/testng/src/test/resources/test_group.xml index 26868375f2..77edb85cdc 100644 --- a/testng/src/test/resources/test_group.xml +++ b/testng/src/test/resources/test_group.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/testng/src/test/resources/test_setup.xml b/testng/src/test/resources/test_setup.xml index 7d9708193e..9197f9fd0e 100644 --- a/testng/src/test/resources/test_setup.xml +++ b/testng/src/test/resources/test_setup.xml @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testng/src/test/resources/test_suite.xml b/testng/src/test/resources/test_suite.xml index 0fe5d1cc40..0ccbbd2714 100644 --- a/testng/src/test/resources/test_suite.xml +++ b/testng/src/test/resources/test_suite.xml @@ -1,9 +1,12 @@ - - - - - - - - + + + + + + + + + + + \ No newline at end of file From 52a3565f39a36487393230d6e0ffc780dfe602c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammet=20O=C4=9Fuz=20=C3=96ZCAN?= Date: Wed, 1 Mar 2017 22:41:28 +0200 Subject: [PATCH 012/291] Seems no conflict (#1274) * Bean Injection Project is added Different Types of Bean Injection article codes are added. * Java-based configuration added Java-based configuration and tests are added. Coding styles are fixed. * List of Lists Article Codes added. List of Lists Article Codes added. * Most popular use case of grouping elements together added Most popular use case of grouping elements together added --- .../list/listoflist/ListOfListsTest.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/core-java/src/test/java/com/baeldung/list/listoflist/ListOfListsTest.java b/core-java/src/test/java/com/baeldung/list/listoflist/ListOfListsTest.java index ce24ff24bc..674a2f89bc 100644 --- a/core-java/src/test/java/com/baeldung/list/listoflist/ListOfListsTest.java +++ b/core-java/src/test/java/com/baeldung/list/listoflist/ListOfListsTest.java @@ -39,7 +39,8 @@ public class ListOfListsTest { @SuppressWarnings("unchecked") @Test public void givenListOfLists_whenRemovingElements_thenCheckNames() { - ((ArrayList) listOfLists.get(1)).remove(0); + + ((ArrayList) listOfLists.get(1)).remove(0); listOfLists.remove(1); assertEquals("Rubber 1", ((Rubber) listOfLists.get(1) .get(0)).getName()); @@ -47,4 +48,29 @@ public class ListOfListsTest { assertEquals("Rubber 1", ((Rubber) listOfLists.get(0) .get(0)).getName()); } + + @Test + public void givenThreeList_whenCombineIntoOneList_thenCheckList() { + ArrayList pens = new ArrayList<>(); + pens.add(new Pen("Pen 1")); + pens.add(new Pen("Pen 2")); + ArrayList pencils = new ArrayList<>(); + pencils.add(new Pencil("Pencil 1")); + pencils.add(new Pencil("Pencil 2")); + ArrayList rubbers = new ArrayList<>(); + rubbers.add(new Rubber("Rubber 1")); + rubbers.add(new Rubber("Rubber 2")); + + List> list = new ArrayList>(); + list.add(pens); + list.add(pencils); + list.add(rubbers); + + assertEquals("Pen 1", ((Pen) list.get(0) + .get(0)).getName()); + assertEquals("Pencil 1", ((Pencil) list.get(1) + .get(0)).getName()); + assertEquals("Rubber 1", ((Rubber) list.get(2) + .get(0)).getName()); + } } From efdd45259f30ea2794a47a4e252831e4f1337210 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Wed, 1 Mar 2017 22:37:00 +0100 Subject: [PATCH 013/291] BAEL-701 - TestNG reformatting --- testng/pom.xml | 196 +++++++++--------- .../java/baeldung/com/MultiThreadedTests.java | 6 +- .../src/test/java/baeldung/com/TestGroup.java | 56 ++--- .../baeldung/reports/CustomisedListener.java | 24 +-- .../baeldung/reports/CustomisedReports.java | 54 ++--- 5 files changed, 168 insertions(+), 168 deletions(-) diff --git a/testng/pom.xml b/testng/pom.xml index 5cf8ab06f3..83b32bb84d 100644 --- a/testng/pom.xml +++ b/testng/pom.xml @@ -1,121 +1,121 @@ - 4.0.0 - com.baeldung - testng - 0.1.0-SNAPSHOT - jar - testng + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.baeldung + testng + 0.1.0-SNAPSHOT + jar + testng - + - + - - org.slf4j - slf4j-api - ${org.slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + - + - - org.testng - testng - ${testng.version} - test - + + org.testng + testng + ${testng.version} + test + - + - - testng - - - src/main/resources - true - - - - - src/main/resources - true - - + + testng + + + src/main/resources + true + + + + + src/main/resources + true + + - + - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - **/*IntegrationTest.java - **/*LongRunningUnitTest.java - **/*ManualTest.java - - - src\test\resources\parametrized_testng.xml - src\test\resources\test_group.xml - src\test\resources\test_setup.xml - src\test\resources\test_suite.xml - + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + + + src\test\resources\parametrized_testng.xml + src\test\resources\test_group.xml + src\test\resources\test_setup.xml + src\test\resources\test_suite.xml + - true - - + true + + - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - prepare-package - - copy-dependencies - - - ${project.build.directory}/libs - - - - - + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/libs + + + + + - + - + - - 1.7.21 - 1.1.7 + + 1.7.21 + 1.1.7 - - 6.10 + + 6.10 - - 3.6.0 - 2.19.1 + + 3.6.0 + 2.19.1 - + \ No newline at end of file diff --git a/testng/src/test/java/baeldung/com/MultiThreadedTests.java b/testng/src/test/java/baeldung/com/MultiThreadedTests.java index 48096b8c20..4476eaa7a0 100644 --- a/testng/src/test/java/baeldung/com/MultiThreadedTests.java +++ b/testng/src/test/java/baeldung/com/MultiThreadedTests.java @@ -4,11 +4,11 @@ import org.testng.Assert; import org.testng.annotations.Test; public class MultiThreadedTests { - + @Test(threadPoolSize = 5, invocationCount = 10, timeOut = 1000) - public void givenMethod_whenRunInThreads_thenCorrect(){ + public void givenMethod_whenRunInThreads_thenCorrect() { int count = Thread.activeCount(); - Assert.assertTrue(count>1); + Assert.assertTrue(count > 1); } } diff --git a/testng/src/test/java/baeldung/com/TestGroup.java b/testng/src/test/java/baeldung/com/TestGroup.java index 014fad7f8b..a592000bed 100644 --- a/testng/src/test/java/baeldung/com/TestGroup.java +++ b/testng/src/test/java/baeldung/com/TestGroup.java @@ -6,39 +6,39 @@ import org.testng.annotations.Test; public class TestGroup { - @BeforeGroups("database") - public void setupDB() { - System.out.println("setupDB()"); - } + @BeforeGroups("database") + public void setupDB() { + System.out.println("setupDB()"); + } - @AfterGroups("database") - public void cleanDB() { - System.out.println("cleanDB()"); - } + @AfterGroups("database") + public void cleanDB() { + System.out.println("cleanDB()"); + } - @Test(groups= "selenium-test") - public void runSelenium() { - System.out.println("runSelenium()"); - } + @Test(groups = "selenium-test") + public void runSelenium() { + System.out.println("runSelenium()"); + } - @Test(groups= "selenium-test") - public void runSelenium1() { - System.out.println("runSelenium()1"); - } + @Test(groups = "selenium-test") + public void runSelenium1() { + System.out.println("runSelenium()1"); + } - @Test(groups = "database") - public void testConnectOracle() { - System.out.println("testConnectOracle()"); - } + @Test(groups = "database") + public void testConnectOracle() { + System.out.println("testConnectOracle()"); + } - @Test(groups = "database") - public void testConnectMsSQL() { - System.out.println("testConnectMsSQL"); - } + @Test(groups = "database") + public void testConnectMsSQL() { + System.out.println("testConnectMsSQL"); + } - @Test(dependsOnGroups = {"database","selenium-test"}) - public void runFinal() { - System.out.println("runFinal"); - } + @Test(dependsOnGroups = {"database", "selenium-test"}) + public void runFinal() { + System.out.println("runFinal"); + } } \ No newline at end of file diff --git a/testng/src/test/java/com/baeldung/reports/CustomisedListener.java b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java index 179ca5f736..e8338c941d 100644 --- a/testng/src/test/java/com/baeldung/reports/CustomisedListener.java +++ b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java @@ -13,25 +13,25 @@ public class CustomisedListener implements ITestListener { public void onFinish(ITestContext arg0) { LOGGER.info("PASSED TEST CASES"); arg0.getPassedTests() - .getAllResults() - .stream() - .forEach(result -> { - LOGGER.info(result.getName()); - }); + .getAllResults() + .stream() + .forEach(result -> { + LOGGER.info(result.getName()); + }); LOGGER.info("FAILED TEST CASES"); arg0.getFailedTests() - .getAllResults() - .stream() - .forEach(result -> { - LOGGER.info(result.getName()); - }); - LOGGER.info("Test completed on: "+arg0.getEndDate().toString()); + .getAllResults() + .stream() + .forEach(result -> { + LOGGER.info(result.getName()); + }); + LOGGER.info("Test completed on: " + arg0.getEndDate().toString()); } @Override public void onStart(ITestContext arg0) { LOGGER.info("Started testing on: " + arg0.getStartDate() - .toString()); + .toString()); } @Override diff --git a/testng/src/test/java/com/baeldung/reports/CustomisedReports.java b/testng/src/test/java/com/baeldung/reports/CustomisedReports.java index e59ecbd79b..07ba2162cc 100644 --- a/testng/src/test/java/com/baeldung/reports/CustomisedReports.java +++ b/testng/src/test/java/com/baeldung/reports/CustomisedReports.java @@ -1,8 +1,5 @@ package com.baeldung.reports; -import java.util.List; -import java.util.Map; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.IReporter; @@ -11,6 +8,9 @@ import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.xml.XmlSuite; +import java.util.List; +import java.util.Map; + public class CustomisedReports implements IReporter { private static final Logger LOGGER = LoggerFactory.getLogger("TEST_REPORT"); @@ -18,32 +18,32 @@ public class CustomisedReports implements IReporter { public void generateReport(List xmlSuites, List suites, String outputDirectory) { suites.stream() - .forEach(suite -> { - String suiteName = suite.getName(); - Map suiteResults = suite.getResults(); - suiteResults.values() - .stream() - .forEach(result -> { - ITestContext context - = ((ISuiteResult) result).getTestContext(); + .forEach(suite -> { + String suiteName = suite.getName(); + Map suiteResults = suite.getResults(); + suiteResults.values() + .stream() + .forEach(result -> { + ITestContext context + = ((ISuiteResult) result).getTestContext(); - LOGGER.info("Passed tests for suite '" - + suiteName + "' is:" - + context.getPassedTests() - .getAllResults() - .size()); - LOGGER.info("Failed tests for suite '" - + suiteName + "' is:" - + context.getFailedTests() - .getAllResults() - .size()); - LOGGER.info("Skipped tests for suite '" - + suiteName + "' is:" - + context.getSkippedTests() - .getAllResults() - .size()); + LOGGER.info("Passed tests for suite '" + + suiteName + "' is:" + + context.getPassedTests() + .getAllResults() + .size()); + LOGGER.info("Failed tests for suite '" + + suiteName + "' is:" + + context.getFailedTests() + .getAllResults() + .size()); + LOGGER.info("Skipped tests for suite '" + + suiteName + "' is:" + + context.getSkippedTests() + .getAllResults() + .size()); + }); }); - }); } From aedbf7874c0b8dfeaa8a08839db8da2482c0acab Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 1 Mar 2017 19:23:26 -0300 Subject: [PATCH 014/291] feat: Create new module 'mockito2' Relates to: BAEL-632 --- mockito2/.gitignore | 14 +++++++ mockito2/README.md | 5 +++ mockito2/pom.xml | 98 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 mockito2/.gitignore create mode 100644 mockito2/README.md create mode 100644 mockito2/pom.xml diff --git a/mockito2/.gitignore b/mockito2/.gitignore new file mode 100644 index 0000000000..7f300600e6 --- /dev/null +++ b/mockito2/.gitignore @@ -0,0 +1,14 @@ +*.class + +.settings +.project + +#folders# +/target +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear diff --git a/mockito2/README.md b/mockito2/README.md new file mode 100644 index 0000000000..587f1341bb --- /dev/null +++ b/mockito2/README.md @@ -0,0 +1,5 @@ +========= + +## Mockito 2 and Java 8 Tips + +Examples on how to leverage Java 8 new features with Mockito version 2 diff --git a/mockito2/pom.xml b/mockito2/pom.xml new file mode 100644 index 0000000000..e116647009 --- /dev/null +++ b/mockito2/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + com.baeldung + mockito2 + 0.0.1-SNAPSHOT + jar + mockito-2-with-java8 + + + + + junit + junit + ${junit.version} + test + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + + + **/*IntegrationTest.java + + + + + + + json + + + + + + + + + + UTF-8 + + + 4.12 + 2.7.5 + + + 3.6.0 + 2.19.1 + + From 6b6b7c79b4396e6b0be4ef6d29f848924f6af981 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 1 Mar 2017 19:28:56 -0300 Subject: [PATCH 015/291] feat: Create Job Position Model and Services Relates to: BAEL-632 --- .../baeldung/mockito/java8/JobPosition.java | 20 +++++++++++++ .../baeldung/mockito/java8/JobService.java | 20 +++++++++++++ .../com/baeldung/mockito/java8/Person.java | 28 +++++++++++++++++++ .../mockito/java8/UnemploymentService.java | 11 ++++++++ .../java8/UnemploymentServiceImpl.java | 26 +++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 mockito2/src/main/java/com/baeldung/mockito/java8/JobPosition.java create mode 100644 mockito2/src/main/java/com/baeldung/mockito/java8/JobService.java create mode 100644 mockito2/src/main/java/com/baeldung/mockito/java8/Person.java create mode 100644 mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java create mode 100644 mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java diff --git a/mockito2/src/main/java/com/baeldung/mockito/java8/JobPosition.java b/mockito2/src/main/java/com/baeldung/mockito/java8/JobPosition.java new file mode 100644 index 0000000000..c7712fa47e --- /dev/null +++ b/mockito2/src/main/java/com/baeldung/mockito/java8/JobPosition.java @@ -0,0 +1,20 @@ +package com.baeldung.mockito.java8; + +public class JobPosition { + private String title; + + public JobPosition() {} + + public JobPosition(String title) { + super(); + this.title = title; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/mockito2/src/main/java/com/baeldung/mockito/java8/JobService.java b/mockito2/src/main/java/com/baeldung/mockito/java8/JobService.java new file mode 100644 index 0000000000..85a59b18a4 --- /dev/null +++ b/mockito2/src/main/java/com/baeldung/mockito/java8/JobService.java @@ -0,0 +1,20 @@ +package com.baeldung.mockito.java8; + +import java.util.Optional; +import java.util.stream.Stream; + +public interface JobService { + Optional findCurrentJobPosition(Person person); + + default boolean assignJobPosition(Person person, JobPosition jobPosition) { + if (!findCurrentJobPosition(person).isPresent()) { + person.setCurrentJobPosition(jobPosition); + + return true; + } else { + return false; + } + } + + Stream listJobs(Person person); +} diff --git a/mockito2/src/main/java/com/baeldung/mockito/java8/Person.java b/mockito2/src/main/java/com/baeldung/mockito/java8/Person.java new file mode 100644 index 0000000000..4f7af49f9d --- /dev/null +++ b/mockito2/src/main/java/com/baeldung/mockito/java8/Person.java @@ -0,0 +1,28 @@ +package com.baeldung.mockito.java8; + +public class Person { + private String name; + private JobPosition currentJobPosition; + + public Person() {} + + public Person(String name) { + this.name = name; + } + + public JobPosition getCurrentJobPosition() { + return currentJobPosition; + } + + public void setCurrentJobPosition(JobPosition currentJobPosition) { + this.currentJobPosition = currentJobPosition; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java b/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java new file mode 100644 index 0000000000..5859ab31b0 --- /dev/null +++ b/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentService.java @@ -0,0 +1,11 @@ +package com.baeldung.mockito.java8; + +import java.util.Optional; + +public interface UnemploymentService { + + boolean personIsEntitledToUnemploymentSupport(Person person); + + Optional searchJob(Person person, String searchString); + +} diff --git a/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java b/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java new file mode 100644 index 0000000000..6f189b46ea --- /dev/null +++ b/mockito2/src/main/java/com/baeldung/mockito/java8/UnemploymentServiceImpl.java @@ -0,0 +1,26 @@ +package com.baeldung.mockito.java8; + +import java.util.Optional; +import java.util.stream.Stream; + +public class UnemploymentServiceImpl implements UnemploymentService { + private final JobService jobService; + + public UnemploymentServiceImpl(JobService jobService) { + this.jobService = jobService; + } + + @Override + public boolean personIsEntitledToUnemploymentSupport(Person person) { + Optional optional = jobService.findCurrentJobPosition(person); + + return !optional.isPresent(); + } + + @Override + public Optional searchJob(Person person, String searchString) { + Stream stream = jobService.listJobs(person); + + return stream.filter((j) -> j.getTitle().contains(searchString)).findFirst(); + } +} From 4b70b1d5ce7089703287739f7f6b84a4e715b8f8 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 1 Mar 2017 19:29:34 -0300 Subject: [PATCH 016/291] feat: Implement example tests for all scenarios Relates to: BAEL-632 --- .../ArgumentMatcherWithLambdaUnitTest.java | 44 +++++++++++++ .../ArgumentMatcherWithoutLambdaUnitTest.java | 55 ++++++++++++++++ .../java8/CustomAnswerWithLambdaUnitTest.java | 45 ++++++++++++++ .../CustomAnswerWithoutLambdaUnitTest.java | 59 ++++++++++++++++++ .../mockito/java8/JobServiceUnitTest.java | 44 +++++++++++++ .../UnemploymentServiceImplUnitTest.java | 62 +++++++++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java create mode 100644 mockito2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java new file mode 100644 index 0000000000..2efac513b7 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithLambdaUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + + +public class ArgumentMatcherWithLambdaUnitTest { + + @InjectMocks + private UnemploymentServiceImpl unemploymentService; + + @Mock + private JobService jobService; + + @Test + public void whenPersonWithJob_thenIsNotEntitled() { + Person peter = new Person("Peter"); + Person linda = new Person("Linda"); + + JobPosition teacher = new JobPosition("Teacher"); + + when(jobService.findCurrentJobPosition( + ArgumentMatchers.argThat((p) -> p.getName().equals("Peter"))) + ).thenReturn(Optional.of(teacher)); + + assertTrue(unemploymentService.personIsEntitledToUnemploymentSupport(linda)); + assertFalse(unemploymentService.personIsEntitledToUnemploymentSupport(peter)); + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } +} diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java new file mode 100644 index 0000000000..f4e8fb4cf5 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + + +public class ArgumentMatcherWithoutLambdaUnitTest { + @InjectMocks + private UnemploymentServiceImpl unemploymentService; + + @Mock + private JobService jobService; + + @Test + public void whenPersonWithJob_thenIsNotEntitled() { + Person peter = new Person("Peter"); + Person linda = new Person("Linda"); + + JobPosition teacher = new JobPosition("Teacher"); + + when(jobService.findCurrentJobPosition( + ArgumentMatchers.argThat(new PeterArgumentMatcher())) + ).thenReturn(Optional.of(teacher)); + + assertTrue(unemploymentService.personIsEntitledToUnemploymentSupport(linda)); + assertFalse(unemploymentService.personIsEntitledToUnemploymentSupport(peter)); + } + + private class PeterArgumentMatcher implements ArgumentMatcher { + @Override + public boolean matches(Person p) { + + if (p.getName().equals("Peter")) { + return true; + } + return false; + } + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } +} diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java new file mode 100644 index 0000000000..eebb86e239 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class CustomAnswerWithLambdaUnitTest { + @InjectMocks + private UnemploymentServiceImpl unemploymentService; + + @Mock + private JobService jobService; + + @Test + public void whenPersonWithJobHistory_thenSearchReturnsValue() { + Person peter = new Person("Peter"); + + assertEquals("Teacher", unemploymentService.searchJob(peter, "").get().getTitle()); + } + + @Test + public void whenPersonWithNoJobHistory_thenSearchReturnsEmpty() { + Person linda = new Person("Linda"); + + assertFalse(unemploymentService.searchJob(linda, "").isPresent()); + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + when(jobService.listJobs(any(Person.class))).then((i) -> { + return ((Person) i.getArgument(0)).getName().equals("Peter") ? Stream. builder().add(new JobPosition("Teacher")).build() : Stream.empty(); + }); + } +} diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java new file mode 100644 index 0000000000..28922bb303 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + + +public class CustomAnswerWithoutLambdaUnitTest { + @InjectMocks + private UnemploymentServiceImpl unemploymentService; + + @Mock + private JobService jobService; + + @Test + public void whenPersonWithJobHistory_thenSearchReturnsValue() { + Person peter = new Person("Peter"); + + assertEquals("Teacher", unemploymentService.searchJob(peter, "").get().getTitle()); + } + + @Test + public void whenPersonWithNoJobHistory_thenSearchReturnsEmpty() { + Person linda = new Person("Linda"); + + assertFalse(unemploymentService.searchJob(linda, "").isPresent()); + } + + private class PersonAnswer implements Answer> { + @Override + public Stream answer(InvocationOnMock invocation) throws Throwable { + Person person = invocation.getArgument(0); + + if(person.getName().equals("Peter")) { + return Stream.builder().add(new JobPosition("Teacher")).build(); + } + + return Stream.empty(); + } + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + when(jobService.listJobs(any(Person.class))).then(new PersonAnswer()); + } +} diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java new file mode 100644 index 0000000000..9ea5c1db47 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/JobServiceUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +public class JobServiceUnitTest { + @Mock + private JobService jobService; + + @Test + public void givenDefaultMethod_whenCallRealMethod_thenNoExceptionIsRaised() { + Person person = new Person(); + + when(jobService.findCurrentJobPosition(person)).thenReturn(Optional.of(new JobPosition())); + doCallRealMethod().when(jobService).assignJobPosition(Mockito.any(Person.class), Mockito.any(JobPosition.class)); + + assertFalse(jobService.assignJobPosition(person, new JobPosition())); + } + + @Test + public void givenReturnIsOfTypeOptional_whenDefaultValueIsReturned_thenValueIsEmpty() { + Person person = new Person(); + + when(jobService.findCurrentJobPosition(person)).thenReturn(Optional.empty()); + doCallRealMethod().when(jobService).assignJobPosition(Mockito.any(Person.class), Mockito.any(JobPosition.class)); + + assertTrue(jobService.assignJobPosition(person, new JobPosition())); + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } +} diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java new file mode 100644 index 0000000000..b3b71e5bf9 --- /dev/null +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/UnemploymentServiceImplUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.mockito.java8; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +import java.util.Optional; +import java.util.stream.Stream; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class UnemploymentServiceImplUnitTest { + @Mock + private JobService jobService; + + @InjectMocks + private UnemploymentServiceImpl unemploymentService; + + @Test + public void givenReturnIsOfTypeOptional_whenMocked_thenValueIsEmpty() { + Person person = new Person(); + + when(jobService.findCurrentJobPosition(any(Person.class))).thenReturn(Optional.empty()); + + assertTrue(unemploymentService.personIsEntitledToUnemploymentSupport(person)); + } + + @Test + public void givenReturnIsOfTypeOptional_whenDefaultValueIsReturned_thenValueIsEmpty() { + Person person = new Person(); + + // This will fail when Mockito 1 is used + assertTrue(unemploymentService.personIsEntitledToUnemploymentSupport(person)); + } + + @Test + public void givenReturnIsOfTypeStream_whenMocked_thenValueIsEmpty() { + Person person = new Person(); + + when(jobService.listJobs(any(Person.class))).thenReturn(Stream.empty()); + + assertFalse(unemploymentService.searchJob(person, "").isPresent()); + } + + @Test + public void givenReturnIsOfTypeStream_whenDefaultValueIsReturned_thenValueIsEmpty() { + Person person = new Person(); + + // This will fail when Mockito 1 is used + assertFalse(unemploymentService.searchJob(person, "").isPresent()); + } + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } +} From 30a692421703b0cb0282b8da287f12f1cf24b44a Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Wed, 1 Mar 2017 20:18:20 -0300 Subject: [PATCH 017/291] feat: Add new module, mockito2, to root pom.xml Resolves: BAEL-632 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 014e4016c5..dfd08926b0 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,7 @@ metrics mesos-marathon mockito + mockito2 mocks orika From 5421a352abcb081b682e7c62b99e21aaf3fe199b Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 1 Mar 2017 22:20:07 -0600 Subject: [PATCH 018/291] BAEL-345: SolrJ (#1263) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md --- .../java/com/baeldung/solrjava/SolrJavaIntegrationTest.java | 2 +- spring-data-rest/README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java index 7f4599a91d..8b5fe77c6f 100644 --- a/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java +++ b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java @@ -33,7 +33,7 @@ public class SolrJavaIntegrationTest { response = solrJavaIntegration.getSolrClient().query(query); SolrDocumentList docList = response.getResults(); - assertEquals(docList.getNumFound(), 1); + assertEquals(1, docList.getNumFound()); for (SolrDocument doc : docList) { assertEquals("Kenmore Dishwasher", (String) doc.getFieldValue("name")); diff --git a/spring-data-rest/README.md b/spring-data-rest/README.md index 4e8828a688..f77c4dc202 100644 --- a/spring-data-rest/README.md +++ b/spring-data-rest/README.md @@ -15,3 +15,4 @@ To view the running application, visit [http://localhost:8080](http://localhost: ###Relevant Articles: - [Guide to Spring Data REST Validators](http://www.baeldung.com/spring-data-rest-validators) +- [Working with Relationships in Spring Data REST](http://www.baeldung.com/spring-data-rest-relationships) From 41bf9ddd6d30cc1c767e6cd42be509df0b500b4f Mon Sep 17 00:00:00 2001 From: Adam InTae Gerard Date: Wed, 1 Mar 2017 22:29:55 -0600 Subject: [PATCH 019/291] BAEL-9 Final (#1262) * BAEL-9 #3 * pom.xml fix * Final --- pom.xml | 2 - spring-boot-servlet/.gitignore | 4 -- spring-boot-servlet/README.md | 2 - spring-boot-servlet/pom.xml | 55 ------------------- .../src/main/java/META-INF/MANIFEST.MF | 2 - .../src/main/resources/application.properties | 10 ---- spring-boot/README.MD | 1 + spring-boot/pom.xml | 18 ++++++ .../baeldung/servlets}/ApplicationMain.java | 4 +- .../configuration/WebAppInitializer.java | 4 +- .../configuration/WebMvcConfigure.java | 3 +- .../baeldung/servlets}/props/Constants.java | 2 +- .../servlets}/props/PropertyLoader.java | 2 +- .../props/PropertySourcesLoader.java | 2 +- .../servlets/GenericCustomServlet.java | 2 +- .../servlets/javaee/AnnotationServlet.java | 2 +- .../servlets/javaee/EEWebXmlServlet.java | 4 +- .../SpringRegistrationBeanServlet.java | 6 +- .../embedded/EmbeddedTomcatExample.java | 2 +- .../src/main/resources/application.properties | 6 +- .../src/main/resources/custom.properties | 0 .../src/main/webapp/WEB-INF/context.xml | 0 .../src/main/webapp/WEB-INF/dispatcher.xml | 0 .../src/main/webapp/WEB-INF/web.xml | 0 .../src/main/webapp/annotationservlet.jsp | 0 .../src/main/webapp/index.jsp | 0 26 files changed, 39 insertions(+), 94 deletions(-) delete mode 100644 spring-boot-servlet/.gitignore delete mode 100644 spring-boot-servlet/README.md delete mode 100644 spring-boot-servlet/pom.xml delete mode 100644 spring-boot-servlet/src/main/java/META-INF/MANIFEST.MF delete mode 100644 spring-boot-servlet/src/main/resources/application.properties rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/ApplicationMain.java (95%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/configuration/WebAppInitializer.java (96%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/configuration/WebMvcConfigure.java (97%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/props/Constants.java (95%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/props/PropertyLoader.java (94%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/props/PropertySourcesLoader.java (95%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/servlets/GenericCustomServlet.java (93%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/servlets/javaee/AnnotationServlet.java (93%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/servlets/javaee/EEWebXmlServlet.java (92%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/servlets/springboot/SpringRegistrationBeanServlet.java (82%) rename {spring-boot-servlet/src/main/java/com/baeldung => spring-boot/src/main/java/com/baeldung/servlets}/servlets/springboot/embedded/EmbeddedTomcatExample.java (90%) rename {spring-boot-servlet => spring-boot}/src/main/resources/custom.properties (100%) rename {spring-boot-servlet => spring-boot}/src/main/webapp/WEB-INF/context.xml (100%) rename {spring-boot-servlet => spring-boot}/src/main/webapp/WEB-INF/dispatcher.xml (100%) rename {spring-boot-servlet => spring-boot}/src/main/webapp/WEB-INF/web.xml (100%) rename {spring-boot-servlet => spring-boot}/src/main/webapp/annotationservlet.jsp (100%) rename {spring-boot-servlet => spring-boot}/src/main/webapp/index.jsp (100%) diff --git a/pom.xml b/pom.xml index 014e4016c5..a392c142d0 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,6 @@ querydsl - reactor-core redis rest-assured rest-testing @@ -111,7 +110,6 @@ spring-autowire spring-batch spring-boot - spring-boot-servlet spring-cloud-data-flow spring-cloud spring-core diff --git a/spring-boot-servlet/.gitignore b/spring-boot-servlet/.gitignore deleted file mode 100644 index 60be5b80aa..0000000000 --- a/spring-boot-servlet/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target/ -.settings/ -.classpath -.project diff --git a/spring-boot-servlet/README.md b/spring-boot-servlet/README.md deleted file mode 100644 index 262a11fc36..0000000000 --- a/spring-boot-servlet/README.md +++ /dev/null @@ -1,2 +0,0 @@ -###Relevant Articles: -- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/how-to-register-a-servlet-in-a-java-web-application/) \ No newline at end of file diff --git a/spring-boot-servlet/pom.xml b/spring-boot-servlet/pom.xml deleted file mode 100644 index 3818e3468f..0000000000 --- a/spring-boot-servlet/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - 4.0.0 - com.baeldung - spring-boot-servlet - 0.0.1-SNAPSHOT - war - spring-boot-servlet - - - org.springframework.boot - spring-boot-dependencies - 1.5.1.RELEASE - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - - org.apache.tomcat.embed - tomcat-embed-core - ${tomcat.version} - - - org.apache.tomcat.embed - tomcat-embed-jasper - ${tomcat.version} - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - UTF-8 - 1.8 - 8.5.11 - - - diff --git a/spring-boot-servlet/src/main/java/META-INF/MANIFEST.MF b/spring-boot-servlet/src/main/java/META-INF/MANIFEST.MF deleted file mode 100644 index 69ebae1751..0000000000 --- a/spring-boot-servlet/src/main/java/META-INF/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: com.baeldung.ApplicationMain diff --git a/spring-boot-servlet/src/main/resources/application.properties b/spring-boot-servlet/src/main/resources/application.properties deleted file mode 100644 index 4e9e2b4cf1..0000000000 --- a/spring-boot-servlet/src/main/resources/application.properties +++ /dev/null @@ -1,10 +0,0 @@ -#Server Configuration -#server.port=8080 -#server.context-path=/javabootdata -#Resource Handling -#spring.resources.static-locations=classpath:/WEB-INF/resources -#spring.mvc.view.prefix=/WEB-INF/ -#spring.mvc.view.suffix=.jsp -#spring.resources.cache-period=3600 -servlet.name=dispatcherExample -servlet.mapping=/dispatcherExampleURL \ No newline at end of file diff --git a/spring-boot/README.MD b/spring-boot/README.MD index d0a02c69fc..78ef3c843c 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -10,3 +10,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [The @ServletComponentScan Annotation in Spring Boot](http://www.baeldung.com/spring-servletcomponentscan) - [A Custom Data Binder in Spring MVC](http://www.baeldung.com/spring-mvc-custom-data-binder) - [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) +- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/how-to-register-a-servlet-in-a-java-web-application/) diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index e77ab10aff..65b0f247f8 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -41,6 +41,24 @@ spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + + org.apache.tomcat.embed + tomcat-embed-jasper + ${tomcat.version} + + io.dropwizard.metrics metrics-core diff --git a/spring-boot-servlet/src/main/java/com/baeldung/ApplicationMain.java b/spring-boot/src/main/java/com/baeldung/servlets/ApplicationMain.java similarity index 95% rename from spring-boot-servlet/src/main/java/com/baeldung/ApplicationMain.java rename to spring-boot/src/main/java/com/baeldung/servlets/ApplicationMain.java index 66f2e85999..a6ea3757fe 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/ApplicationMain.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/ApplicationMain.java @@ -1,4 +1,4 @@ -package com.baeldung; +package com.baeldung.servlets; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -16,4 +16,4 @@ public class ApplicationMain extends SpringBootServletInitializer { protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(ApplicationMain.class); } -} \ No newline at end of file +} diff --git a/spring-boot-servlet/src/main/java/com/baeldung/configuration/WebAppInitializer.java b/spring-boot/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java similarity index 96% rename from spring-boot-servlet/src/main/java/com/baeldung/configuration/WebAppInitializer.java rename to spring-boot/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java index b7e22500f4..eadd40355a 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/configuration/WebAppInitializer.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java @@ -1,4 +1,4 @@ -package com.baeldung.configuration; +package com.baeldung.servlets.configuration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; @@ -29,4 +29,4 @@ public class WebAppInitializer implements WebApplicationInitializer { servletTwo.addMapping("/"); } -} \ No newline at end of file +} diff --git a/spring-boot-servlet/src/main/java/com/baeldung/configuration/WebMvcConfigure.java b/spring-boot/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java similarity index 97% rename from spring-boot-servlet/src/main/java/com/baeldung/configuration/WebMvcConfigure.java rename to spring-boot/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java index de9067de6e..3d6a10c2ac 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/configuration/WebMvcConfigure.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java @@ -1,4 +1,4 @@ -package com.baeldung.configuration; +package com.baeldung.servlets.configuration; import org.springframework.boot.web.support.ErrorPageFilter; import org.springframework.context.annotation.Bean; @@ -37,4 +37,3 @@ public class WebMvcConfigure extends WebMvcConfigurerAdapter { return new ErrorPageFilter(); } } - diff --git a/spring-boot-servlet/src/main/java/com/baeldung/props/Constants.java b/spring-boot/src/main/java/com/baeldung/servlets/props/Constants.java similarity index 95% rename from spring-boot-servlet/src/main/java/com/baeldung/props/Constants.java rename to spring-boot/src/main/java/com/baeldung/servlets/props/Constants.java index 421401eec7..6345d1f969 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/props/Constants.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/props/Constants.java @@ -1,4 +1,4 @@ -package com.baeldung.props; +package com.baeldung.servlets.props; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-boot-servlet/src/main/java/com/baeldung/props/PropertyLoader.java b/spring-boot/src/main/java/com/baeldung/servlets/props/PropertyLoader.java similarity index 94% rename from spring-boot-servlet/src/main/java/com/baeldung/props/PropertyLoader.java rename to spring-boot/src/main/java/com/baeldung/servlets/props/PropertyLoader.java index 5d890d96fa..c29da45929 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/props/PropertyLoader.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/props/PropertyLoader.java @@ -1,4 +1,4 @@ -package com.baeldung.props; +package com.baeldung.servlets.props; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/spring-boot-servlet/src/main/java/com/baeldung/props/PropertySourcesLoader.java b/spring-boot/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java similarity index 95% rename from spring-boot-servlet/src/main/java/com/baeldung/props/PropertySourcesLoader.java rename to spring-boot/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java index 8c7b3a4af5..56a6751326 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/props/PropertySourcesLoader.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java @@ -1,4 +1,4 @@ -package com.baeldung.props; +package com.baeldung.servlets.props; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/spring-boot-servlet/src/main/java/com/baeldung/servlets/GenericCustomServlet.java b/spring-boot/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java similarity index 93% rename from spring-boot-servlet/src/main/java/com/baeldung/servlets/GenericCustomServlet.java rename to spring-boot/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java index c6543c9eef..49dd9404b7 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/servlets/GenericCustomServlet.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java @@ -1,4 +1,4 @@ -package com.baeldung.servlets; +package com.baeldung.servlets.servlets; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; diff --git a/spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/AnnotationServlet.java b/spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java similarity index 93% rename from spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/AnnotationServlet.java rename to spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java index d971e68cfa..b50a7d5454 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/AnnotationServlet.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java @@ -1,4 +1,4 @@ -package com.baeldung.servlets.javaee; +package com.baeldung.servlets.servlets.javaee; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; diff --git a/spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/EEWebXmlServlet.java b/spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java similarity index 92% rename from spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/EEWebXmlServlet.java rename to spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java index 4209e815cd..c7b373064f 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/servlets/javaee/EEWebXmlServlet.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java @@ -1,4 +1,4 @@ -package com.baeldung.servlets.javaee; +package com.baeldung.servlets.servlets.javaee; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -17,4 +17,4 @@ public class EEWebXmlServlet extends HttpServlet { PrintWriter out = response.getWriter(); out.println("

Hello World

"); } -} \ No newline at end of file +} diff --git a/spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/SpringRegistrationBeanServlet.java b/spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java similarity index 82% rename from spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/SpringRegistrationBeanServlet.java rename to spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java index 4a34465894..e3c225d429 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/SpringRegistrationBeanServlet.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java @@ -1,6 +1,6 @@ -package com.baeldung.servlets.springboot; +package com.baeldung.servlets.servlets.springboot; -import com.baeldung.servlets.GenericCustomServlet; +import com.baeldung.servlets.servlets.GenericCustomServlet; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,5 +15,3 @@ public class SpringRegistrationBeanServlet { return bean; } } - - diff --git a/spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/embedded/EmbeddedTomcatExample.java b/spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java similarity index 90% rename from spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/embedded/EmbeddedTomcatExample.java rename to spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java index b2458f33c7..9e460d03a8 100644 --- a/spring-boot-servlet/src/main/java/com/baeldung/servlets/springboot/embedded/EmbeddedTomcatExample.java +++ b/spring-boot/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java @@ -1,4 +1,4 @@ -package com.baeldung.servlets.springboot.embedded; +package com.baeldung.servlets.servlets.springboot.embedded; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; diff --git a/spring-boot/src/main/resources/application.properties b/spring-boot/src/main/resources/application.properties index d30045d1dc..8c6549f53d 100644 --- a/spring-boot/src/main/resources/application.properties +++ b/spring-boot/src/main/resources/application.properties @@ -28,4 +28,8 @@ security.user.name=admin1 security.user.password=secret1 management.security.role=SUPERUSER -logging.level.org.springframework=INFO \ No newline at end of file +logging.level.org.springframework=INFO + +#Servlet Configuration +servlet.name=dispatcherExample +servlet.mapping=/dispatcherExampleURL diff --git a/spring-boot-servlet/src/main/resources/custom.properties b/spring-boot/src/main/resources/custom.properties similarity index 100% rename from spring-boot-servlet/src/main/resources/custom.properties rename to spring-boot/src/main/resources/custom.properties diff --git a/spring-boot-servlet/src/main/webapp/WEB-INF/context.xml b/spring-boot/src/main/webapp/WEB-INF/context.xml similarity index 100% rename from spring-boot-servlet/src/main/webapp/WEB-INF/context.xml rename to spring-boot/src/main/webapp/WEB-INF/context.xml diff --git a/spring-boot-servlet/src/main/webapp/WEB-INF/dispatcher.xml b/spring-boot/src/main/webapp/WEB-INF/dispatcher.xml similarity index 100% rename from spring-boot-servlet/src/main/webapp/WEB-INF/dispatcher.xml rename to spring-boot/src/main/webapp/WEB-INF/dispatcher.xml diff --git a/spring-boot-servlet/src/main/webapp/WEB-INF/web.xml b/spring-boot/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from spring-boot-servlet/src/main/webapp/WEB-INF/web.xml rename to spring-boot/src/main/webapp/WEB-INF/web.xml diff --git a/spring-boot-servlet/src/main/webapp/annotationservlet.jsp b/spring-boot/src/main/webapp/annotationservlet.jsp similarity index 100% rename from spring-boot-servlet/src/main/webapp/annotationservlet.jsp rename to spring-boot/src/main/webapp/annotationservlet.jsp diff --git a/spring-boot-servlet/src/main/webapp/index.jsp b/spring-boot/src/main/webapp/index.jsp similarity index 100% rename from spring-boot-servlet/src/main/webapp/index.jsp rename to spring-boot/src/main/webapp/index.jsp From 73e195b190a58899a24fbbf699a67ac1081e0524 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Thu, 2 Mar 2017 05:49:21 +0100 Subject: [PATCH 020/291] BAEL-574 - Removing obsolete test --- .../bootstrap/gateway/IntegrationTest.java | 201 ------------------ 1 file changed, 201 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java deleted file mode 100644 index 16057edc48..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.gateway; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.apache.http.entity.ContentType; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.*; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -public class IntegrationTest { - - private TestRestTemplate testRestTemplate = new TestRestTemplate(); - private String testUrl = "http://localhost:8080"; - - @Test - public void testAccess() throws Exception { - ResponseEntity response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //try the protected resource and confirm the redirect to login - response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class); - Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode()); - Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0)); - - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "user"); - form.add("password", "password"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - HttpEntity httpEntity = new HttpEntity<>(headers); - - addBook(); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - addRatings(); - - //request the admin protected resource to determine it is still protected - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); - - //login as the admin - form.clear(); - form.add("username", "admin"); - form.add("password", "admin"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - httpEntity = new HttpEntity<>(headers); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //request the discovery resources as the admin - response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - } - - private void addRatings() { - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "user"); - form.add("password", "password"); - ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); - Rating rating = new Rating(1L, 4); - - HttpEntity httpEntity = new HttpEntity<>(rating, headers); - - //request the protected resource - ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/rating-service/ratings", httpEntity, Rating.class); - Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); - Assert.assertEquals(rating.getBookId(), bookResponse.getBody().getBookId()); - Assert.assertEquals(rating.getStars(), bookResponse.getBody().getStars()); - } - - private void addBook(){ - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "admin"); - form.add("password", "admin"); - ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); - Book book = new Book("Baeldung", "How to spring cloud"); - - HttpEntity httpEntity = new HttpEntity<>(book, headers); - - //request the protected resource - ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/book-service/books", httpEntity, Book.class); - Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); - Assert.assertEquals(book.getAuthor(), bookResponse.getBody().getAuthor()); - Assert.assertEquals(book.getTitle(), bookResponse.getBody().getTitle()); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Book { - - private Long id; - private String author; - private String title; - - public Book() { - } - - public Book(String author, String title) { - this.author = author; - this.title = title; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Rating { - private Long id; - private Long bookId; - private int stars; - - public Rating() { - } - - public Rating(Long bookId, int stars) { - this.bookId = bookId; - this.stars = stars; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getBookId() { - return bookId; - } - - public void setBookId(Long bookId) { - this.bookId = bookId; - } - - public int getStars() { - return stars; - } - - public void setStars(int stars) { - this.stars = stars; - } - } - - -} \ No newline at end of file From d99c87777f1e9d8cfa61e70894c84e5e80678cca Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Thu, 2 Mar 2017 10:53:24 +0100 Subject: [PATCH 021/291] BAEL-311 add exampe of one way encryption --- .../java/org/baeldung/jasypt/JasyptTest.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java index d05b18171d..c4bed5de83 100644 --- a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java +++ b/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java @@ -3,21 +3,24 @@ package org.baeldung.jasypt; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; +import org.jasypt.util.password.BasicPasswordEncryptor; import org.jasypt.util.text.BasicTextEncryptor; import org.junit.Ignore; import org.junit.Test; +import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotSame; +import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; public class JasyptTest { @Test - public void givenTextPassword_whenDecrypt_shouldCompareToEncrypted() { + public void givenTextPassword_whenDecrypt_thenCompareToEncrypted() { //given BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); String password = "secret-pass"; - textEncryptor.setPasswordCharArray(password.toCharArray()); + textEncryptor.setPasswordCharArray("some-random-password".toCharArray()); //when String myEncryptedText = textEncryptor.encrypt(password); @@ -28,10 +31,37 @@ public class JasyptTest { assertEquals(plainText, password); } + @Test + public void givenTextPassword_whenOneWayEncryption_thenCompareEncryptedPasswordsShouldBeSame(){ + String password = "secret-pass"; + BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor(); + String encryptedPassword = passwordEncryptor.encryptPassword(password); + + //when + boolean result = passwordEncryptor.checkPassword("secret-pass", encryptedPassword); + + //then + assertTrue(result); + } + + @Test + public void givenTextPassword_whenOneWayEncryption_thenCompareEncryptedPasswordsShouldNotBeSame(){ + String password = "secret-pass"; + BasicPasswordEncryptor passwordEncryptor = new BasicPasswordEncryptor(); + String encryptedPassword = passwordEncryptor.encryptPassword(password); + + //when + boolean result = passwordEncryptor.checkPassword("secret-pass-not-same", encryptedPassword); + + //then + assertFalse(result); + } + + @Test @Ignore("should have installed local_policy.jar") - public void givenTextPassword_whenDecrypt_shouldCompareToEncryptedWithCustomAlgorithm() { + public void givenTextPassword_whenDecrypt_thenCompareToEncryptedWithCustomAlgorithm() { //given StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); String password = "secret-pass"; @@ -49,7 +79,7 @@ public class JasyptTest { @Test @Ignore("should have installed local_policy.jar") - public void givenTextPassword_whenDecryptOnHighPerformance_shouldDecrypt(){ + public void givenTextPassword_whenDecryptOnHighPerformance_thenDecrypt(){ //given String password = "secret-pass"; PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); From 08c63209efce2ebed5355cfa7c55d3af68c4203b Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Thu, 2 Mar 2017 09:11:46 -0600 Subject: [PATCH 022/291] BAEL-345: README.md (#1280) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md --- apache-solrj/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 apache-solrj/README.md diff --git a/apache-solrj/README.md b/apache-solrj/README.md new file mode 100644 index 0000000000..7a32becb64 --- /dev/null +++ b/apache-solrj/README.md @@ -0,0 +1,4 @@ +## Apache Solrj Tutorials Project + +### Relevant Articles +- [Guide to Solr in Java with Apache Solrj](http://www.baeldung.com/apache-solrj) From f1322a34a6da51b0a93b90637ee790b5dcf08d47 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Thu, 2 Mar 2017 09:49:46 -0600 Subject: [PATCH 023/291] Reinstate module reactor-core in main pom (#1283) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 16dc0a50d0..b0156a4289 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,7 @@ querydsl + reactor-core redis rest-assured rest-testing From 1df0503b202f6615f0870bbfe843597ec9596519 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 2 Mar 2017 12:06:22 -0400 Subject: [PATCH 024/291] Java Money & Currency --- .../.resourceCache/ECBCurrentRateProvider.dat | 60 ++--- .../ECBHistoric90RateProvider.dat | 8 +- .../IMFHistoricRateProvider.dat | 204 ++++++++--------- core-java/.resourceCache/IMFRateProvider.dat | 204 ++++++++--------- .../com/baeldung/money/JavaMoneyTest.java | 208 +++++++++++++----- 5 files changed, 396 insertions(+), 288 deletions(-) diff --git a/core-java/.resourceCache/ECBCurrentRateProvider.dat b/core-java/.resourceCache/ECBCurrentRateProvider.dat index 45cf516ac8..69eed9a0d8 100644 --- a/core-java/.resourceCache/ECBCurrentRateProvider.dat +++ b/core-java/.resourceCache/ECBCurrentRateProvider.dat @@ -5,38 +5,38 @@ European Central Bank - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core-java/.resourceCache/ECBHistoric90RateProvider.dat b/core-java/.resourceCache/ECBHistoric90RateProvider.dat index f51c2eacfa..157cac1a6a 100644 --- a/core-java/.resourceCache/ECBHistoric90RateProvider.dat +++ b/core-java/.resourceCache/ECBHistoric90RateProvider.dat @@ -1,4 +1,6 @@ -Reference ratesEuropean Central Bank +Reference ratesEuropean Central Bank + + @@ -58,6 +60,4 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/core-java/.resourceCache/IMFHistoricRateProvider.dat b/core-java/.resourceCache/IMFHistoricRateProvider.dat index 4c98b3b04e..12809d35af 100644 --- a/core-java/.resourceCache/IMFHistoricRateProvider.dat +++ b/core-java/.resourceCache/IMFHistoricRateProvider.dat @@ -2,113 +2,113 @@ SDRs per Currency unit and Currency units per SDR (1) last five days SDRs per Currency unit (2) -Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 -Chinese Yuan 0.1075530000 0.1074200000 0.1076250000 0.1077740000 0.1075920000 -Euro 0.7826360000 0.7829640000 0.7824120000 0.7793410000 0.7806080000 -Japanese Yen 0.0065915500 0.0065398200 0.0065279600 0.0065267800 0.0065271000 -U.K. Pound Sterling 0.9178430000 0.9263250000 0.9233090000 0.9217470000 0.9201430000 -U.S. Dollar 0.7392420000 0.7380190000 0.7400090000 0.7413120000 0.7408260000 -Algerian Dinar 0.0067056800 0.0067170500 0.0067108200 0.0067122300 -Australian Dollar 0.5695290000 0.5688450000 0.5701430000 0.5680650000 -Bahrain Dinar 1.9628200000 1.9681100000 1.9715700000 1.9702800000 -Botswana Pula 0.0712926000 0.0714849000 0.0710918000 0.0708970000 -Brazilian Real 0.2409310000 0.2401220000 0.2394110000 0.2396560000 -Brunei Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 -Canadian Dollar 0.5632010000 0.5645050000 0.5621540000 0.5634090000 -Chilean Peso 0.0011525100 0.0011535400 0.0011517700 0.0011535600 -Colombian Peso 0.0002570000 0.0002557440 0.0002553890 0.0002552100 -Czech Koruna 0.0289783000 0.0289564000 0.0288448000 0.0288889000 -Danish Krone 0.1053170000 0.1052550000 0.1048460000 0.1050150000 -Hungarian Forint 0.0025337100 0.0025343600 0.0025357900 0.0025387300 -Icelandic Krona 0.0068082900 0.0067593100 0.0067227000 0.0066885700 -Indian Rupee 0.0110722000 0.0110702000 -Indonesian Rupiah 0.0000553404 0.0000553899 0.0000555040 0.0000554096 -Iranian Rial 0.0000228786 0.0000228671 -Israeli New Sheqel 0.1995720000 0.1995710000 0.1998150000 0.1998450000 -Kazakhstani Tenge 0.0023693200 0.0023668900 0.0023601900 0.0023350800 -Korean Won 0.0006480670 0.0006486190 0.0006464180 0.0006455440 -Kuwaiti Dinar 2.4165700000 2.4230800000 2.4273500000 2.4257600000 +Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 +Chinese Yuan 0.1078010000 0.1075250000 0.1075530000 0.1074200000 +Euro 0.7811130000 0.7827060000 0.7826360000 0.7829640000 +Japanese Yen 0.0065627100 0.0065625100 0.0065915500 0.0065398200 +U.K. Pound Sterling 0.9132630000 0.9188320000 0.9178430000 0.9263250000 +U.S. Dollar 0.7415860000 0.7386110000 0.7392420000 0.7380190000 +Algerian Dinar 0.0067127200 0.0067093100 0.0067141700 0.0067056800 +Australian Dollar 0.5677580000 0.5678440000 0.5688470000 0.5695290000 +Bahrain Dinar 1.9723000000 1.9643900000 1.9660700000 1.9628200000 +Botswana Pula 0.0711181000 0.0711282000 0.0712629000 0.0712926000 +Brazilian Real 0.2393220000 0.2383620000 0.2385650000 0.2409310000 +Brunei Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 +Canadian Dollar 0.5575260000 0.5642640000 0.5632010000 +Chilean Peso 0.0011428700 0.0011448000 0.0011449400 0.0011525100 +Colombian Peso 0.0002540400 0.0002550210 0.0002561010 0.0002570000 +Czech Koruna 0.0289072000 0.0289685000 0.0289649000 0.0289783000 +Danish Krone 0.1050820000 0.1052990000 0.1052900000 0.1053170000 +Hungarian Forint 0.0025403700 0.0025419400 0.0025407000 0.0025337100 +Icelandic Krona 0.0069632500 0.0069197200 0.0068709200 0.0068082900 +Indian Rupee 0.0110936000 0.0110674000 0.0110790000 +Indonesian Rupiah 0.0000555038 0.0000553391 0.0000554196 0.0000553404 +Iranian Rial 0.0000228835 0.0000227945 0.0000228133 +Israeli New Sheqel 0.2041810000 0.2018610000 0.2009360000 0.1995720000 +Kazakhstani Tenge 0.0023615900 0.0023658000 0.0023693200 +Korean Won 0.0006524260 0.0006536180 0.0006480670 +Kuwaiti Dinar 2.4274500000 2.4193000000 2.4213600000 2.4165700000 Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1659960000 0.1662940000 0.1663250000 0.1661230000 -Mauritian Rupee 0.0208418000 -Mexican Peso 0.0372107000 0.0375618000 0.0372281000 0.0362282000 -Nepalese Rupee 0.0069012400 0.0069030700 0.0069229700 0.0069139200 -New Zealand Dollar 0.5331450000 0.5322880000 0.5307790000 0.5306540000 -Norwegian Krone 0.0886062000 0.0888398000 0.0884082000 0.0885668000 -Rial Omani 1.9194300000 1.9246000000 1.9279900000 1.9267300000 -Pakistani Rupee 0.0070384300 0.0070575400 0.0070700400 0.0070658600 -Nuevo Sol 0.2283980000 0.2287290000 0.2281570000 -Philippine Peso 0.0146922000 0.0147295000 0.0147363000 0.0147628000 -Polish Zloty 0.1814160000 0.1811970000 0.1812540000 0.1809450000 -Qatar Riyal 0.2027520000 0.2032990000 0.2036570000 0.2035240000 -Russian Ruble 0.0128977000 0.0128040000 -Saudi Arabian Riyal 0.1968050000 0.1973360000 0.1976830000 0.1975540000 -Singapore Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 -South African Rand 0.0569347000 0.0570889000 0.0566127000 0.0562263000 -Sri Lanka Rupee 0.0048931100 0.0049014800 0.0049020900 -Swedish Krona 0.0822544000 0.0824642000 0.0823543000 0.0824973000 -Swiss Franc 0.7345670000 0.7331180000 0.7312210000 0.7337090000 -Thai Baht 0.0211098000 0.0211467000 0.0211707000 0.0211393000 -Trinidad And Tobago Dollar 0.1092030000 0.1091300000 0.1093820000 0.1095510000 -Tunisian Dinar 0.3206630000 0.3204540000 0.3225790000 0.3234230000 -U.A.E. Dirham 0.2009580000 0.2015000000 0.2018550000 0.2017230000 -Peso Uruguayo 0.0259816000 0.0261108000 0.0261517000 -Bolivar Fuerte 0.0739869000 0.0741864000 +Malaysian Ringgit 0.1667420000 0.1661670000 0.1663840000 0.1659960000 +Mauritian Rupee 0.0208473000 0.0207651000 0.0207673000 +Mexican Peso 0.0369385000 0.0372748000 0.0372107000 +Nepalese Rupee 0.0069436900 0.0069210200 0.0069133300 0.0069012400 +New Zealand Dollar 0.5305310000 0.5304700000 0.5318850000 0.5331450000 +Norwegian Krone 0.0881434000 0.0882493000 0.0885500000 0.0886062000 +Rial Omani 1.9287000000 1.9209600000 1.9226100000 1.9194300000 +Pakistani Rupee 0.0070732900 0.0070443600 0.0070502500 0.0070384300 +Nuevo Sol 0.2266370000 0.2274590000 0.2271530000 +Philippine Peso 0.0147565000 0.0146938000 0.0147268000 0.0146922000 +Polish Zloty 0.1819580000 0.1811650000 0.1814310000 0.1814160000 +Qatar Riyal 0.2037320000 0.2029150000 0.2030880000 0.2027520000 +Russian Ruble 0.0127033000 0.0127429000 0.0127594000 +Saudi Arabian Riyal 0.1977560000 0.1969630000 0.1971310000 0.1968050000 +Singapore Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 +South African Rand 0.0567982000 0.0567078000 0.0569908000 0.0569347000 +Sri Lanka Rupee 0.0049030500 0.0048833800 0.0048875500 +Swedish Krona 0.0818510000 0.0817029000 0.0818978000 0.0822544000 +Swiss Franc 0.7340980000 0.7348630000 0.7341760000 0.7345670000 +Thai Baht 0.0211936000 0.0211661000 0.0212042000 0.0211098000 +Trinidad And Tobago Dollar 0.1102220000 0.1092030000 +Tunisian Dinar 0.3225800000 0.3211100000 0.3215340000 0.3206630000 +U.A.E. Dirham 0.2019290000 0.2011190000 0.2012910000 0.2009580000 +Peso Uruguayo 0.0258745000 +Bolivar Fuerte 0.0743445000 0.0740462000 0.0741095000 0.0739869000 Currency units per SDR(3) -Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 -Chinese Yuan 9.297740 9.309250 9.291520 9.278680 9.294370 -Euro 1.277730 1.277200 1.278100 1.283140 1.281050 -Japanese Yen 151.709000 152.909000 153.187000 153.215000 153.207000 -U.K. Pound Sterling 1.089510 1.079530 1.083060 1.084900 1.086790 -U.S. Dollar 1.352740 1.354980 1.351330 1.348960 1.349840 -Algerian Dinar 149.127000 148.875000 149.013000 148.982000 -Australian Dollar 1.755840 1.757950 1.753950 1.760360 -Bahrain Dinar 0.509471 0.508102 0.507210 0.507542 -Botswana Pula 14.026700 13.989000 14.066300 14.105000 -Brazilian Real 4.150570 4.164550 4.176920 4.172650 -Brunei Dollar 1.903340 1.911870 1.913900 1.917730 -Canadian Dollar 1.775570 1.771460 1.778870 1.774910 -Chilean Peso 867.671000 866.897000 868.229000 866.882000 -Colombian Peso 3,891.050000 3,910.160000 3,915.600000 3,918.340000 -Czech Koruna 34.508600 34.534700 34.668300 34.615400 -Danish Krone 9.495140 9.500740 9.537800 9.522450 -Hungarian Forint 394.678000 394.577000 394.354000 393.898000 -Icelandic Krona 146.880000 147.944000 148.750000 149.509000 -Indian Rupee 90.316300 90.332600 -Indonesian Rupiah 18,070.000000 18,053.800000 18,016.700000 18,047.400000 -Iranian Rial 43,709.000000 43,730.900000 -Israeli New Sheqel 5.010720 5.010750 5.004630 5.003880 -Kazakhstani Tenge 422.062000 422.495000 423.695000 428.251000 -Korean Won 1,543.050000 1,541.740000 1,546.990000 1,549.080000 -Kuwaiti Dinar 0.413810 0.412698 0.411972 0.412242 +Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 +Chinese Yuan 9.276350 9.300160 9.297740 9.309250 +Euro 1.280220 1.277620 1.277730 1.277200 +Japanese Yen 152.376000 152.381000 151.709000 152.909000 +U.K. Pound Sterling 1.094970 1.088340 1.089510 1.079530 +U.S. Dollar 1.348460 1.353890 1.352740 1.354980 +Algerian Dinar 148.971000 149.047000 148.939000 149.127000 +Australian Dollar 1.761310 1.761050 1.757940 1.755840 +Bahrain Dinar 0.507022 0.509064 0.508629 0.509471 +Botswana Pula 14.061100 14.059100 14.032500 14.026700 +Brazilian Real 4.178470 4.195300 4.191730 4.150570 +Brunei Dollar 1.897550 1.900870 1.900460 1.903340 +Canadian Dollar 1.793640 1.772220 1.775570 +Chilean Peso 874.990000 873.515000 873.408000 867.671000 +Colombian Peso 3,936.390000 3,921.250000 3,904.710000 3,891.050000 +Czech Koruna 34.593500 34.520300 34.524500 34.508600 +Danish Krone 9.516380 9.496770 9.497580 9.495140 +Hungarian Forint 393.643000 393.400000 393.592000 394.678000 +Icelandic Krona 143.611000 144.515000 145.541000 146.880000 +Indian Rupee 90.142100 90.355500 90.260900 +Indonesian Rupiah 18,016.800000 18,070.400000 18,044.200000 18,070.000000 +Iranian Rial 43,699.600000 43,870.200000 43,834.100000 +Israeli New Sheqel 4.897620 4.953900 4.976710 5.010720 +Kazakhstani Tenge 423.444000 422.690000 422.062000 +Korean Won 1,532.740000 1,529.950000 1,543.050000 +Kuwaiti Dinar 0.411955 0.413343 0.412991 0.413810 Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 6.024240 6.013450 6.012330 6.019640 -Mauritian Rupee 47.980500 -Mexican Peso 26.874000 26.622800 26.861400 27.602800 -Nepalese Rupee 144.901000 144.863000 144.447000 144.636000 -New Zealand Dollar 1.875660 1.878680 1.884020 1.884470 -Norwegian Krone 11.285900 11.256200 11.311200 11.290900 -Rial Omani 0.520988 0.519588 0.518675 0.519014 -Pakistani Rupee 142.077000 141.692000 141.442000 141.526000 -Nuevo Sol 4.378320 4.371990 4.382950 -Philippine Peso 68.063300 67.891000 67.859600 67.737800 -Polish Zloty 5.512190 5.518860 5.517120 5.526540 -Qatar Riyal 4.932130 4.918860 4.910220 4.913430 -Russian Ruble 77.533200 78.100600 -Saudi Arabian Riyal 5.081170 5.067500 5.058600 5.061910 -Singapore Dollar 1.903340 1.911870 1.913900 1.917730 -South African Rand 17.564000 17.516500 17.663900 17.785300 -Sri Lanka Rupee 204.369000 204.020000 203.995000 -Swedish Krona 12.157400 12.126500 12.142700 12.121600 -Swiss Franc 1.361350 1.364040 1.367580 1.362940 -Thai Baht 47.371400 47.288700 47.235100 47.305300 -Trinidad And Tobago Dollar 9.157260 9.163380 9.142270 9.128170 -Tunisian Dinar 3.118540 3.120570 3.100020 3.091930 -U.A.E. Dirham 4.976160 4.962780 4.954050 4.957290 -Peso Uruguayo 38.488800 38.298300 38.238400 -Bolivar Fuerte 13.515900 13.479600 +Malaysian Ringgit 5.997290 6.018040 6.010190 6.024240 +Mauritian Rupee 47.967800 48.157700 48.152600 +Mexican Peso 27.072000 26.827800 26.874000 +Nepalese Rupee 144.016000 144.487000 144.648000 144.901000 +New Zealand Dollar 1.884900 1.885120 1.880110 1.875660 +Norwegian Krone 11.345100 11.331500 11.293100 11.285900 +Rial Omani 0.518484 0.520573 0.520126 0.520988 +Pakistani Rupee 141.377000 141.958000 141.839000 142.077000 +Nuevo Sol 4.412340 4.396400 4.402320 +Philippine Peso 67.766700 68.055900 67.903400 68.063300 +Polish Zloty 5.495770 5.519830 5.511740 5.512190 +Qatar Riyal 4.908410 4.928170 4.923970 4.932130 +Russian Ruble 78.719700 78.475100 78.373600 +Saudi Arabian Riyal 5.056740 5.077100 5.072770 5.081170 +Singapore Dollar 1.897550 1.900870 1.900460 1.903340 +South African Rand 17.606200 17.634300 17.546700 17.564000 +Sri Lanka Rupee 203.955000 204.776000 204.601000 +Swedish Krona 12.217300 12.239500 12.210300 12.157400 +Swiss Franc 1.362220 1.360800 1.362070 1.361350 +Thai Baht 47.184100 47.245400 47.160500 47.371400 +Trinidad And Tobago Dollar 9.072600 9.157260 +Tunisian Dinar 3.100010 3.114200 3.110090 3.118540 +U.A.E. Dirham 4.952240 4.972180 4.967930 4.976160 +Peso Uruguayo 38.648100 +Bolivar Fuerte 13.450900 13.505100 13.493500 13.515900 (1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. diff --git a/core-java/.resourceCache/IMFRateProvider.dat b/core-java/.resourceCache/IMFRateProvider.dat index 4c98b3b04e..12809d35af 100644 --- a/core-java/.resourceCache/IMFRateProvider.dat +++ b/core-java/.resourceCache/IMFRateProvider.dat @@ -2,113 +2,113 @@ SDRs per Currency unit and Currency units per SDR (1) last five days SDRs per Currency unit (2) -Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 -Chinese Yuan 0.1075530000 0.1074200000 0.1076250000 0.1077740000 0.1075920000 -Euro 0.7826360000 0.7829640000 0.7824120000 0.7793410000 0.7806080000 -Japanese Yen 0.0065915500 0.0065398200 0.0065279600 0.0065267800 0.0065271000 -U.K. Pound Sterling 0.9178430000 0.9263250000 0.9233090000 0.9217470000 0.9201430000 -U.S. Dollar 0.7392420000 0.7380190000 0.7400090000 0.7413120000 0.7408260000 -Algerian Dinar 0.0067056800 0.0067170500 0.0067108200 0.0067122300 -Australian Dollar 0.5695290000 0.5688450000 0.5701430000 0.5680650000 -Bahrain Dinar 1.9628200000 1.9681100000 1.9715700000 1.9702800000 -Botswana Pula 0.0712926000 0.0714849000 0.0710918000 0.0708970000 -Brazilian Real 0.2409310000 0.2401220000 0.2394110000 0.2396560000 -Brunei Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 -Canadian Dollar 0.5632010000 0.5645050000 0.5621540000 0.5634090000 -Chilean Peso 0.0011525100 0.0011535400 0.0011517700 0.0011535600 -Colombian Peso 0.0002570000 0.0002557440 0.0002553890 0.0002552100 -Czech Koruna 0.0289783000 0.0289564000 0.0288448000 0.0288889000 -Danish Krone 0.1053170000 0.1052550000 0.1048460000 0.1050150000 -Hungarian Forint 0.0025337100 0.0025343600 0.0025357900 0.0025387300 -Icelandic Krona 0.0068082900 0.0067593100 0.0067227000 0.0066885700 -Indian Rupee 0.0110722000 0.0110702000 -Indonesian Rupiah 0.0000553404 0.0000553899 0.0000555040 0.0000554096 -Iranian Rial 0.0000228786 0.0000228671 -Israeli New Sheqel 0.1995720000 0.1995710000 0.1998150000 0.1998450000 -Kazakhstani Tenge 0.0023693200 0.0023668900 0.0023601900 0.0023350800 -Korean Won 0.0006480670 0.0006486190 0.0006464180 0.0006455440 -Kuwaiti Dinar 2.4165700000 2.4230800000 2.4273500000 2.4257600000 +Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 +Chinese Yuan 0.1078010000 0.1075250000 0.1075530000 0.1074200000 +Euro 0.7811130000 0.7827060000 0.7826360000 0.7829640000 +Japanese Yen 0.0065627100 0.0065625100 0.0065915500 0.0065398200 +U.K. Pound Sterling 0.9132630000 0.9188320000 0.9178430000 0.9263250000 +U.S. Dollar 0.7415860000 0.7386110000 0.7392420000 0.7380190000 +Algerian Dinar 0.0067127200 0.0067093100 0.0067141700 0.0067056800 +Australian Dollar 0.5677580000 0.5678440000 0.5688470000 0.5695290000 +Bahrain Dinar 1.9723000000 1.9643900000 1.9660700000 1.9628200000 +Botswana Pula 0.0711181000 0.0711282000 0.0712629000 0.0712926000 +Brazilian Real 0.2393220000 0.2383620000 0.2385650000 0.2409310000 +Brunei Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 +Canadian Dollar 0.5575260000 0.5642640000 0.5632010000 +Chilean Peso 0.0011428700 0.0011448000 0.0011449400 0.0011525100 +Colombian Peso 0.0002540400 0.0002550210 0.0002561010 0.0002570000 +Czech Koruna 0.0289072000 0.0289685000 0.0289649000 0.0289783000 +Danish Krone 0.1050820000 0.1052990000 0.1052900000 0.1053170000 +Hungarian Forint 0.0025403700 0.0025419400 0.0025407000 0.0025337100 +Icelandic Krona 0.0069632500 0.0069197200 0.0068709200 0.0068082900 +Indian Rupee 0.0110936000 0.0110674000 0.0110790000 +Indonesian Rupiah 0.0000555038 0.0000553391 0.0000554196 0.0000553404 +Iranian Rial 0.0000228835 0.0000227945 0.0000228133 +Israeli New Sheqel 0.2041810000 0.2018610000 0.2009360000 0.1995720000 +Kazakhstani Tenge 0.0023615900 0.0023658000 0.0023693200 +Korean Won 0.0006524260 0.0006536180 0.0006480670 +Kuwaiti Dinar 2.4274500000 2.4193000000 2.4213600000 2.4165700000 Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1659960000 0.1662940000 0.1663250000 0.1661230000 -Mauritian Rupee 0.0208418000 -Mexican Peso 0.0372107000 0.0375618000 0.0372281000 0.0362282000 -Nepalese Rupee 0.0069012400 0.0069030700 0.0069229700 0.0069139200 -New Zealand Dollar 0.5331450000 0.5322880000 0.5307790000 0.5306540000 -Norwegian Krone 0.0886062000 0.0888398000 0.0884082000 0.0885668000 -Rial Omani 1.9194300000 1.9246000000 1.9279900000 1.9267300000 -Pakistani Rupee 0.0070384300 0.0070575400 0.0070700400 0.0070658600 -Nuevo Sol 0.2283980000 0.2287290000 0.2281570000 -Philippine Peso 0.0146922000 0.0147295000 0.0147363000 0.0147628000 -Polish Zloty 0.1814160000 0.1811970000 0.1812540000 0.1809450000 -Qatar Riyal 0.2027520000 0.2032990000 0.2036570000 0.2035240000 -Russian Ruble 0.0128977000 0.0128040000 -Saudi Arabian Riyal 0.1968050000 0.1973360000 0.1976830000 0.1975540000 -Singapore Dollar 0.5253930000 0.5230480000 0.5224920000 0.5214510000 -South African Rand 0.0569347000 0.0570889000 0.0566127000 0.0562263000 -Sri Lanka Rupee 0.0048931100 0.0049014800 0.0049020900 -Swedish Krona 0.0822544000 0.0824642000 0.0823543000 0.0824973000 -Swiss Franc 0.7345670000 0.7331180000 0.7312210000 0.7337090000 -Thai Baht 0.0211098000 0.0211467000 0.0211707000 0.0211393000 -Trinidad And Tobago Dollar 0.1092030000 0.1091300000 0.1093820000 0.1095510000 -Tunisian Dinar 0.3206630000 0.3204540000 0.3225790000 0.3234230000 -U.A.E. Dirham 0.2009580000 0.2015000000 0.2018550000 0.2017230000 -Peso Uruguayo 0.0259816000 0.0261108000 0.0261517000 -Bolivar Fuerte 0.0739869000 0.0741864000 +Malaysian Ringgit 0.1667420000 0.1661670000 0.1663840000 0.1659960000 +Mauritian Rupee 0.0208473000 0.0207651000 0.0207673000 +Mexican Peso 0.0369385000 0.0372748000 0.0372107000 +Nepalese Rupee 0.0069436900 0.0069210200 0.0069133300 0.0069012400 +New Zealand Dollar 0.5305310000 0.5304700000 0.5318850000 0.5331450000 +Norwegian Krone 0.0881434000 0.0882493000 0.0885500000 0.0886062000 +Rial Omani 1.9287000000 1.9209600000 1.9226100000 1.9194300000 +Pakistani Rupee 0.0070732900 0.0070443600 0.0070502500 0.0070384300 +Nuevo Sol 0.2266370000 0.2274590000 0.2271530000 +Philippine Peso 0.0147565000 0.0146938000 0.0147268000 0.0146922000 +Polish Zloty 0.1819580000 0.1811650000 0.1814310000 0.1814160000 +Qatar Riyal 0.2037320000 0.2029150000 0.2030880000 0.2027520000 +Russian Ruble 0.0127033000 0.0127429000 0.0127594000 +Saudi Arabian Riyal 0.1977560000 0.1969630000 0.1971310000 0.1968050000 +Singapore Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 +South African Rand 0.0567982000 0.0567078000 0.0569908000 0.0569347000 +Sri Lanka Rupee 0.0049030500 0.0048833800 0.0048875500 +Swedish Krona 0.0818510000 0.0817029000 0.0818978000 0.0822544000 +Swiss Franc 0.7340980000 0.7348630000 0.7341760000 0.7345670000 +Thai Baht 0.0211936000 0.0211661000 0.0212042000 0.0211098000 +Trinidad And Tobago Dollar 0.1102220000 0.1092030000 +Tunisian Dinar 0.3225800000 0.3211100000 0.3215340000 0.3206630000 +U.A.E. Dirham 0.2019290000 0.2011190000 0.2012910000 0.2009580000 +Peso Uruguayo 0.0258745000 +Bolivar Fuerte 0.0743445000 0.0740462000 0.0741095000 0.0739869000 Currency units per SDR(3) -Currency February 27, 2017 February 24, 2017 February 23, 2017 February 22, 2017 February 21, 2017 -Chinese Yuan 9.297740 9.309250 9.291520 9.278680 9.294370 -Euro 1.277730 1.277200 1.278100 1.283140 1.281050 -Japanese Yen 151.709000 152.909000 153.187000 153.215000 153.207000 -U.K. Pound Sterling 1.089510 1.079530 1.083060 1.084900 1.086790 -U.S. Dollar 1.352740 1.354980 1.351330 1.348960 1.349840 -Algerian Dinar 149.127000 148.875000 149.013000 148.982000 -Australian Dollar 1.755840 1.757950 1.753950 1.760360 -Bahrain Dinar 0.509471 0.508102 0.507210 0.507542 -Botswana Pula 14.026700 13.989000 14.066300 14.105000 -Brazilian Real 4.150570 4.164550 4.176920 4.172650 -Brunei Dollar 1.903340 1.911870 1.913900 1.917730 -Canadian Dollar 1.775570 1.771460 1.778870 1.774910 -Chilean Peso 867.671000 866.897000 868.229000 866.882000 -Colombian Peso 3,891.050000 3,910.160000 3,915.600000 3,918.340000 -Czech Koruna 34.508600 34.534700 34.668300 34.615400 -Danish Krone 9.495140 9.500740 9.537800 9.522450 -Hungarian Forint 394.678000 394.577000 394.354000 393.898000 -Icelandic Krona 146.880000 147.944000 148.750000 149.509000 -Indian Rupee 90.316300 90.332600 -Indonesian Rupiah 18,070.000000 18,053.800000 18,016.700000 18,047.400000 -Iranian Rial 43,709.000000 43,730.900000 -Israeli New Sheqel 5.010720 5.010750 5.004630 5.003880 -Kazakhstani Tenge 422.062000 422.495000 423.695000 428.251000 -Korean Won 1,543.050000 1,541.740000 1,546.990000 1,549.080000 -Kuwaiti Dinar 0.413810 0.412698 0.411972 0.412242 +Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 +Chinese Yuan 9.276350 9.300160 9.297740 9.309250 +Euro 1.280220 1.277620 1.277730 1.277200 +Japanese Yen 152.376000 152.381000 151.709000 152.909000 +U.K. Pound Sterling 1.094970 1.088340 1.089510 1.079530 +U.S. Dollar 1.348460 1.353890 1.352740 1.354980 +Algerian Dinar 148.971000 149.047000 148.939000 149.127000 +Australian Dollar 1.761310 1.761050 1.757940 1.755840 +Bahrain Dinar 0.507022 0.509064 0.508629 0.509471 +Botswana Pula 14.061100 14.059100 14.032500 14.026700 +Brazilian Real 4.178470 4.195300 4.191730 4.150570 +Brunei Dollar 1.897550 1.900870 1.900460 1.903340 +Canadian Dollar 1.793640 1.772220 1.775570 +Chilean Peso 874.990000 873.515000 873.408000 867.671000 +Colombian Peso 3,936.390000 3,921.250000 3,904.710000 3,891.050000 +Czech Koruna 34.593500 34.520300 34.524500 34.508600 +Danish Krone 9.516380 9.496770 9.497580 9.495140 +Hungarian Forint 393.643000 393.400000 393.592000 394.678000 +Icelandic Krona 143.611000 144.515000 145.541000 146.880000 +Indian Rupee 90.142100 90.355500 90.260900 +Indonesian Rupiah 18,016.800000 18,070.400000 18,044.200000 18,070.000000 +Iranian Rial 43,699.600000 43,870.200000 43,834.100000 +Israeli New Sheqel 4.897620 4.953900 4.976710 5.010720 +Kazakhstani Tenge 423.444000 422.690000 422.062000 +Korean Won 1,532.740000 1,529.950000 1,543.050000 +Kuwaiti Dinar 0.411955 0.413343 0.412991 0.413810 Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 6.024240 6.013450 6.012330 6.019640 -Mauritian Rupee 47.980500 -Mexican Peso 26.874000 26.622800 26.861400 27.602800 -Nepalese Rupee 144.901000 144.863000 144.447000 144.636000 -New Zealand Dollar 1.875660 1.878680 1.884020 1.884470 -Norwegian Krone 11.285900 11.256200 11.311200 11.290900 -Rial Omani 0.520988 0.519588 0.518675 0.519014 -Pakistani Rupee 142.077000 141.692000 141.442000 141.526000 -Nuevo Sol 4.378320 4.371990 4.382950 -Philippine Peso 68.063300 67.891000 67.859600 67.737800 -Polish Zloty 5.512190 5.518860 5.517120 5.526540 -Qatar Riyal 4.932130 4.918860 4.910220 4.913430 -Russian Ruble 77.533200 78.100600 -Saudi Arabian Riyal 5.081170 5.067500 5.058600 5.061910 -Singapore Dollar 1.903340 1.911870 1.913900 1.917730 -South African Rand 17.564000 17.516500 17.663900 17.785300 -Sri Lanka Rupee 204.369000 204.020000 203.995000 -Swedish Krona 12.157400 12.126500 12.142700 12.121600 -Swiss Franc 1.361350 1.364040 1.367580 1.362940 -Thai Baht 47.371400 47.288700 47.235100 47.305300 -Trinidad And Tobago Dollar 9.157260 9.163380 9.142270 9.128170 -Tunisian Dinar 3.118540 3.120570 3.100020 3.091930 -U.A.E. Dirham 4.976160 4.962780 4.954050 4.957290 -Peso Uruguayo 38.488800 38.298300 38.238400 -Bolivar Fuerte 13.515900 13.479600 +Malaysian Ringgit 5.997290 6.018040 6.010190 6.024240 +Mauritian Rupee 47.967800 48.157700 48.152600 +Mexican Peso 27.072000 26.827800 26.874000 +Nepalese Rupee 144.016000 144.487000 144.648000 144.901000 +New Zealand Dollar 1.884900 1.885120 1.880110 1.875660 +Norwegian Krone 11.345100 11.331500 11.293100 11.285900 +Rial Omani 0.518484 0.520573 0.520126 0.520988 +Pakistani Rupee 141.377000 141.958000 141.839000 142.077000 +Nuevo Sol 4.412340 4.396400 4.402320 +Philippine Peso 67.766700 68.055900 67.903400 68.063300 +Polish Zloty 5.495770 5.519830 5.511740 5.512190 +Qatar Riyal 4.908410 4.928170 4.923970 4.932130 +Russian Ruble 78.719700 78.475100 78.373600 +Saudi Arabian Riyal 5.056740 5.077100 5.072770 5.081170 +Singapore Dollar 1.897550 1.900870 1.900460 1.903340 +South African Rand 17.606200 17.634300 17.546700 17.564000 +Sri Lanka Rupee 203.955000 204.776000 204.601000 +Swedish Krona 12.217300 12.239500 12.210300 12.157400 +Swiss Franc 1.362220 1.360800 1.362070 1.361350 +Thai Baht 47.184100 47.245400 47.160500 47.371400 +Trinidad And Tobago Dollar 9.072600 9.157260 +Tunisian Dinar 3.100010 3.114200 3.110090 3.118540 +U.A.E. Dirham 4.952240 4.972180 4.967930 4.976160 +Peso Uruguayo 38.648100 +Bolivar Fuerte 13.450900 13.505100 13.493500 13.515900 (1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index 5aa12095ff..ed737c6184 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -1,69 +1,177 @@ package com.baeldung.money; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import java.math.BigDecimal; +import java.util.Locale; + +import javax.money.CurrencyUnit; +import javax.money.Monetary; +import javax.money.MonetaryAmount; +import javax.money.UnknownCurrencyException; import javax.money.convert.ConversionQueryBuilder; +import javax.money.convert.CurrencyConversion; import javax.money.convert.MonetaryConversions; +import javax.money.format.AmountFormatQueryBuilder; +import javax.money.format.MonetaryAmountFormat; +import javax.money.format.MonetaryFormats; +import org.javamoney.moneta.FastMoney; +import org.javamoney.moneta.Money; +import org.javamoney.moneta.format.CurrencyStyle; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; -import com.baeldung.money.JavaMoney; - -import junit.framework.TestCase; - -public class JavaMoneyTest -{ +public class JavaMoneyTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); @Test - public void givenAmountsAreCorrect() - { - JavaMoney j9m; - j9m = new JavaMoney(); - assertEquals("USD", j9m.USD.toString()); - assertEquals("USD 1", j9m.oneDolar.toString()); - assertEquals("EUR 1", j9m.oneEuro.toString()); - assertEquals("USD 200.5", j9m.fstAmtUSD.toString()); - assertEquals("EUR 1.30473908", j9m.fstAmtEUR.toString()); - assertEquals("USD 12", j9m.moneyof.toString()); - assertEquals("USD 2.00000", j9m.fastmoneyof.toString()); + public void givenCurrencyCode_whenString_thanExist() { + CurrencyUnit USD = Monetary.getCurrency("USD"); + assertNotNull(USD); + assertEquals(USD.getCurrencyCode(), "USD"); + assertEquals(USD.getNumericCode(), 840); + assertEquals(USD.getDefaultFractionDigits(), 2); + assertFalse(Monetary.isCurrencyAvailable("AAA")); + + } + + @Test + public void givenCurrencyCode_whenNoExist_thanThrowsError() { + thrown.expect(UnknownCurrencyException.class); + CurrencyUnit AAA = Monetary.getCurrency("AAA"); + assertNull(AAA); + throw new UnknownCurrencyException("AAA"); + } + + @Test + public void givenAmounts_whenStrinfied_thanEquals() { + CurrencyUnit USD = Monetary.getCurrency("USD"); + MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); + MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + Money moneyof = Money.of(12, USD); + FastMoney fastmoneyof = FastMoney.of(2, USD); + Money oneEuro = Money.of(1, "EUR"); + + assertEquals("USD", USD.toString()); + assertEquals("USD 1", oneDolar.toString()); + assertEquals("EUR 1", oneEuro.toString()); + assertEquals("USD 200.5", fstAmtUSD.toString()); + assertEquals("EUR 1.30473908", fstAmtEUR.toString()); + assertEquals("USD 12", moneyof.toString()); + assertEquals("USD 2.00000", fastmoneyof.toString()); + + } + + @Test + public void givenCurrencies_whenCompared_thanNotequal() { + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + Money oneEuro = Money.of(1, "EUR"); + assertFalse(oneEuro.equals(FastMoney.of(1, "EUR"))); + assertTrue(oneDolar.equals(Money.of(1, "USD"))); + + } + + @Test + public void givenAmount_whenDivided_thanThrowsException() { + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + thrown.expect(ArithmeticException.class); + MonetaryAmount oneDivThree = oneDolar.divide(3); + assertNull(oneDivThree); + throw new ArithmeticException(); + + } + + @Test + public void givenArithmetic_whenStrinfied_thanEqualsAmount() { + CurrencyUnit USD = Monetary.getCurrency("USD"); + Money moneyof = Money.of(12, USD); + MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); + Money calcAmtUSD = Money.of(1, "USD").subtract(fstAmtUSD); + FastMoney fastmoneyof = FastMoney.of(2, USD); + MonetaryAmount calcMoneyFastMoney = moneyof.subtract(fastmoneyof); + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); + MonetaryAmount divideAmount = oneDolar.divide(0.25); + MonetaryAmount[] monetaryAmounts = new MonetaryAmount[] { + Money.of(100, "CHF"), + Money.of(10.20, "CHF"), + Money.of(1.15, "CHF"), }; + + Money sumAmtCHF = Money.of(0, "CHF"); + + for (MonetaryAmount monetaryAmount : monetaryAmounts) { + sumAmtCHF = sumAmtCHF.add(monetaryAmount); + } + assertEquals("USD", USD.toString()); + assertEquals("USD 1", oneDolar.toString()); + assertEquals("USD 200.5", fstAmtUSD.toString()); + assertEquals("USD 12", moneyof.toString()); + assertEquals("USD 2.00000", fastmoneyof.toString()); + assertEquals("USD -199.5", calcAmtUSD.toString()); + assertEquals("CHF 111.35", sumAmtCHF.toString()); + assertEquals("USD 10", calcMoneyFastMoney.toString()); + assertEquals("USD 0.25", multiplyAmount.toString()); + assertEquals("USD 4", divideAmount.toString()); } - + @Test - public void givenArithmeticIsCorrect(){ - JavaMoney j9m; - j9m = new JavaMoney(); - assertEquals("USD -199.5", j9m.calcAmtUSD.toString()); - assertEquals("CHF 111.35", j9m.sumAmtCHF.toString()); - assertEquals("USD 10", j9m.calcMoneyFastMoney.toString()); - assertEquals("USD 0.25", j9m.multiplyAmount.toString()); - assertEquals("USD 4", j9m.divideAmount.toString()); + public void givenAmount_whenRounded_thanEquals() { + MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + MonetaryAmount roundEUR = fstAmtEUR.with(Monetary.getDefaultRounding()); + assertEquals("EUR 1.30473908", fstAmtEUR.toString()); + assertEquals("EUR 1.3", roundEUR.toString()); } - + @Test - public void givenRoundingIsCorrect(){ - JavaMoney j9m; - j9m = new JavaMoney(); - assertEquals("EUR 1.3", j9m.roundEUR.toString()); + public void givenAmount_whenCustomFormat_thanEquals() { + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmountFormat formatUSD = MonetaryFormats.getAmountFormat(Locale.US); + String usFormatted = formatUSD.format(oneDolar); + + MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern", "00000.00 ¤").build()); + String customFormatted = customFormat.format(oneDolar); + + assertEquals("USD 1", oneDolar.toString()); + assertNotNull(formatUSD); + assertNotNull(customFormat); + assertEquals("USD1.00", usFormatted); + assertEquals("00001.00 US Dollar", customFormatted); } - + @Test - public void givenFormatIsCorrect(){ - JavaMoney j9m; - j9m = new JavaMoney(); - assertEquals("USD1.00", j9m.usFormatted); - assertEquals("00001.00 US Dollar", j9m.customFormatted); - } - - @Test - public void givenConversionIsNotNull(){ - JavaMoney j9m; - j9m = new JavaMoney(); - assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build())); - assertNotNull(MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("USD").build())); - assertNotNull(j9m.convertedAmountEURtoUSD); - assertNotNull(j9m.convertedAmountEURtoUSD2); - assertNotNull(j9m.convertedAmountUSDtoEUR); - assertNotNull(j9m.convertedAmountUSDtoEUR2); + public void givenAmount_whenConversion_thenNotNull() { + CurrencyUnit USD = Monetary.getCurrency("USD"); + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + + CurrencyConversion convEUR = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build()); + CurrencyConversion convUSD = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency(USD).build()); + + CurrencyConversion conversionUSD = MonetaryConversions.getConversion("USD"); + CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR"); + + MonetaryAmount convertedAmountEURtoUSD = fstAmtEUR.with(conversionUSD); + MonetaryAmount convertedAmountEURtoUSD2 = fstAmtEUR.with(convUSD); + MonetaryAmount convertedAmountUSDtoEUR = oneDolar.with(conversionEUR); + MonetaryAmount convertedAmountUSDtoEUR2 = oneDolar.with(convEUR); + + assertEquals("USD", USD.toString()); + assertEquals("USD 1", oneDolar.toString()); + assertEquals("EUR 1.30473908", fstAmtEUR.toString()); + assertNotNull(convEUR); + assertNotNull(convUSD); + assertNotNull(convertedAmountEURtoUSD); + assertNotNull(convertedAmountEURtoUSD2); + assertNotNull(convertedAmountUSDtoEUR); + assertNotNull(convertedAmountUSDtoEUR2); } } From 351af60bcea9dd7e54abf75c3a54fc222bf5d613 Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Thu, 2 Mar 2017 18:16:06 -0300 Subject: [PATCH 025/291] refactor: Use 'of' instead of Stream 'builder' Simplify the construction of a Stream by using the 'of()' method instead of a 'builder' Resolves: BAEL-632 --- .../baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java index eebb86e239..b4e5abdc6c 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java @@ -39,7 +39,7 @@ public class CustomAnswerWithLambdaUnitTest { MockitoAnnotations.initMocks(this); when(jobService.listJobs(any(Person.class))).then((i) -> { - return ((Person) i.getArgument(0)).getName().equals("Peter") ? Stream. builder().add(new JobPosition("Teacher")).build() : Stream.empty(); + return ((Person) i.getArgument(0)).getName().equals("Peter") ? Stream.of(new JobPosition("Teacher")) : Stream.empty(); }); } } From 23489a082bf1776addc0cee74bec94341934f7ce Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Fri, 3 Mar 2017 00:21:28 +0100 Subject: [PATCH 026/291] BEAL-75 - Spring Boot Audit Support (#1240) * BEAL-75 - Spring Boot Audit Support Source code for http://inprogress.baeldung.com/wp-admin/post.php?post=35337&action=edit * BEAL-75 - Spring Boot Audit Support Update to use SLF4J logger instead of System.out.println --- spring-boot-auditing/.gitignore | 6 + spring-boot-auditing/pom.xml | 198 ++++++++++++++++++ .../main/java/org/baeldung/Application.java | 13 ++ .../src/main/java/org/baeldung/MvcConfig.java | 18 ++ .../java/org/baeldung/WebSecurityConfig.java | 34 +++ ...temptedPathAuthorizationAuditListener.java | 36 ++++ .../auditing/LoginAttemptsLogger.java | 25 +++ .../src/main/resources/application.properties | 1 + .../src/main/resources/logback.xml | 14 ++ .../src/main/resources/templates/hello.html | 13 ++ .../src/main/resources/templates/home.html | 11 + .../src/main/resources/templates/login.html | 20 ++ 12 files changed, 389 insertions(+) create mode 100644 spring-boot-auditing/.gitignore create mode 100644 spring-boot-auditing/pom.xml create mode 100755 spring-boot-auditing/src/main/java/org/baeldung/Application.java create mode 100755 spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java create mode 100755 spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java create mode 100644 spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java create mode 100644 spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java create mode 100644 spring-boot-auditing/src/main/resources/application.properties create mode 100644 spring-boot-auditing/src/main/resources/logback.xml create mode 100755 spring-boot-auditing/src/main/resources/templates/hello.html create mode 100755 spring-boot-auditing/src/main/resources/templates/home.html create mode 100755 spring-boot-auditing/src/main/resources/templates/login.html diff --git a/spring-boot-auditing/.gitignore b/spring-boot-auditing/.gitignore new file mode 100644 index 0000000000..31ce405488 --- /dev/null +++ b/spring-boot-auditing/.gitignore @@ -0,0 +1,6 @@ +/target/ +.settings/ +.classpath +.project +*.iml +.idea \ No newline at end of file diff --git a/spring-boot-auditing/pom.xml b/spring-boot-auditing/pom.xml new file mode 100644 index 0000000000..9307db39ee --- /dev/null +++ b/spring-boot-auditing/pom.xml @@ -0,0 +1,198 @@ + + 4.0.0 + com.baeldung + spring-boot-auditing + 0.0.1-SNAPSHOT + war + spring-boot-auditing + This is simple boot application for Spring boot auditing test + + + + org.springframework.boot + spring-boot-starter-parent + 1.5.1.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-security + + + + io.dropwizard.metrics + metrics-core + + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter + + + com.jayway.jsonpath + json-path + test + + + org.springframework.boot + spring-boot-starter-mail + + + org.subethamail + subethasmtp + ${subethasmtp.version} + test + + + + org.webjars + bootstrap + ${bootstrap.version} + + + org.webjars + jquery + ${jquery.version} + + + + org.apache.tomcat + tomcat-servlet-api + ${tomee-servlet-api.version} + provided + + + + + + spring-boot + + + src/main/resources + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-war-plugin + + + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + + + **/*IntegrationTest.java + + + + + + + json + + + + + + + + + + + UTF-8 + 1.8 + 4.3.4.RELEASE + 2.2.1 + 3.1.1 + 3.3.7-1 + 3.1.7 + 8.5.11 + + + diff --git a/spring-boot-auditing/src/main/java/org/baeldung/Application.java b/spring-boot-auditing/src/main/java/org/baeldung/Application.java new file mode 100755 index 0000000000..bf7b7bd1a6 --- /dev/null +++ b/spring-boot-auditing/src/main/java/org/baeldung/Application.java @@ -0,0 +1,13 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) throws Throwable { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java b/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java new file mode 100755 index 0000000000..fecb8c5c0b --- /dev/null +++ b/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java @@ -0,0 +1,18 @@ +package org.baeldung; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +public class MvcConfig extends WebMvcConfigurerAdapter { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/home").setViewName("home"); + registry.addViewController("/").setViewName("home"); + registry.addViewController("/hello").setViewName("hello"); + registry.addViewController("/login").setViewName("login"); + } + +} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java b/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java new file mode 100755 index 0000000000..199edce0bc --- /dev/null +++ b/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java @@ -0,0 +1,34 @@ +package org.baeldung; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/", "/home").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login") + .permitAll() + .and() + .logout() + .permitAll(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } +} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java b/spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java new file mode 100644 index 0000000000..bc36ac08b3 --- /dev/null +++ b/spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java @@ -0,0 +1,36 @@ +package org.baeldung.auditing; + +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener; +import org.springframework.security.access.event.AbstractAuthorizationEvent; +import org.springframework.security.access.event.AuthorizationFailureEvent; +import org.springframework.security.web.FilterInvocation; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class ExposeAttemptedPathAuthorizationAuditListener extends AbstractAuthorizationAuditListener { + + public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; + + @Override + public void onApplicationEvent(AbstractAuthorizationEvent event) { + if (event instanceof AuthorizationFailureEvent) { + onAuthorizationFailureEvent((AuthorizationFailureEvent) event); + } + } + + private void onAuthorizationFailureEvent(AuthorizationFailureEvent event) { + Map data = new HashMap<>(); + data.put("type", event.getAccessDeniedException().getClass().getName()); + data.put("message", event.getAccessDeniedException().getMessage()); + data.put("requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() ); + if (event.getAuthentication().getDetails() != null) { + data.put("details", event.getAuthentication().getDetails()); + } + publish(new AuditEvent(event.getAuthentication().getName(), AUTHORIZATION_FAILURE, + data)); + } +} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java b/spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java new file mode 100644 index 0000000000..5be8cebfd3 --- /dev/null +++ b/spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java @@ -0,0 +1,25 @@ +package org.baeldung.auditing; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent; +import org.springframework.context.event.EventListener; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +@Component +public class LoginAttemptsLogger { + private static final Logger LOGGER = LoggerFactory.getLogger(LoginAttemptsLogger.class); + + @EventListener + public void auditEventHappened(AuditApplicationEvent auditApplicationEvent) { + AuditEvent auditEvent = auditApplicationEvent.getAuditEvent(); + LOGGER.debug("Principal " + auditEvent.getPrincipal() + " - " + auditEvent.getType()); + + WebAuthenticationDetails details = (WebAuthenticationDetails) auditEvent.getData().get("details"); + LOGGER.debug(" Remote IP address: " + details.getRemoteAddress()); + LOGGER.debug(" Session Id: " + details.getSessionId()); + LOGGER.debug(" Request URL: " + auditEvent.getData().get("requestUrl")); + } +} diff --git a/spring-boot-auditing/src/main/resources/application.properties b/spring-boot-auditing/src/main/resources/application.properties new file mode 100644 index 0000000000..cf09473b60 --- /dev/null +++ b/spring-boot-auditing/src/main/resources/application.properties @@ -0,0 +1 @@ +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/logback.xml b/spring-boot-auditing/src/main/resources/logback.xml new file mode 100644 index 0000000000..78913ee76f --- /dev/null +++ b/spring-boot-auditing/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/hello.html b/spring-boot-auditing/src/main/resources/templates/hello.html new file mode 100755 index 0000000000..46feef7e2c --- /dev/null +++ b/spring-boot-auditing/src/main/resources/templates/hello.html @@ -0,0 +1,13 @@ + + + + Hello World! + + +

Hello [[${#httpServletRequest.remoteUser}]]!

+
+ +
+ + \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/home.html b/spring-boot-auditing/src/main/resources/templates/home.html new file mode 100755 index 0000000000..fe4e8b337e --- /dev/null +++ b/spring-boot-auditing/src/main/resources/templates/home.html @@ -0,0 +1,11 @@ + + + + Spring Security Example + + +

Welcome!

+ +

Click here to see a greeting.

+ + \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/login.html b/spring-boot-auditing/src/main/resources/templates/login.html new file mode 100755 index 0000000000..a1785313f5 --- /dev/null +++ b/spring-boot-auditing/src/main/resources/templates/login.html @@ -0,0 +1,20 @@ + + + + Spring Security Example + + +
+ Invalid username and password. +
+
+ You have been logged out. +
+
+
+
+
+
+ + \ No newline at end of file From 6356fb6a26c68b6efb0ecb0e33de263183e23bd3 Mon Sep 17 00:00:00 2001 From: k0l0ssus Date: Thu, 2 Mar 2017 23:20:59 -0500 Subject: [PATCH 027/291] Guice Intro (#1177) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * Update pom.xml * Update pom.xml * Update pom.xml --- guice-intro/pom.xml | 34 +++++++++++ .../java/com/baeldung/examples/RunGuice.java | 36 ++++++++++++ .../examples/guice/Communication.java | 57 +++++++++++++++++++ .../examples/guice/CommunicationMode.java | 12 ++++ .../examples/guice/DefaultCommunicator.java | 48 ++++++++++++++++ .../guice/EmailCommunicationMode.java | 23 ++++++++ .../examples/guice/IMCommunicationMode.java | 30 ++++++++++ .../examples/guice/SMSCommunicationMode.java | 29 ++++++++++ .../examples/guice/aop/MessageLogger.java | 22 +++++++ .../guice/aop/MessageSentLoggable.java | 16 ++++++ .../examples/guice/binding/AOPModule.java | 22 +++++++ .../examples/guice/binding/BasicModule.java | 36 ++++++++++++ .../guice/constant/CommunicationModel.java | 16 ++++++ .../examples/guice/marker/Communicator.java | 11 ++++ .../examples/guice/modules/BasicModule.java | 37 ++++++++++++ 15 files changed, 429 insertions(+) create mode 100644 guice-intro/pom.xml create mode 100644 guice-intro/src/main/java/com/baeldung/examples/RunGuice.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java create mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java diff --git a/guice-intro/pom.xml b/guice-intro/pom.xml new file mode 100644 index 0000000000..1f0d7679b7 --- /dev/null +++ b/guice-intro/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + com.baeldung.examples.guice + guice-intro + 1.0-SNAPSHOT + jar + + + com.google.inject + guice + ${guice.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + UTF-8 + 1.8 + 1.8 + 4.1.0 + + guice-intro + diff --git a/guice-intro/src/main/java/com/baeldung/examples/RunGuice.java b/guice-intro/src/main/java/com/baeldung/examples/RunGuice.java new file mode 100644 index 0000000000..b4b3e8571e --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/RunGuice.java @@ -0,0 +1,36 @@ + +package com.baeldung.examples; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.binding.AOPModule; +import com.baeldung.examples.guice.modules.BasicModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import java.util.Scanner; + +/** + * + * @author Baeldung + */ +public class RunGuice { + + public static void main(String[] args) { + Injector injector = Guice.createInjector(new BasicModule(), new AOPModule()); + Communication comms = injector.getInstance(Communication.class); + Scanner scanner = new Scanner(System.in); + System.out.println("Enter your message to be sent; press Q to quit and P to print the message log"); + while (true) { + String input = scanner.nextLine(); + if (input.equalsIgnoreCase("q")) { + System.exit(0); + } + if (input.equalsIgnoreCase("p")) { + comms.print(); + } else { + comms.sendMessage(input); + } + + } + + } +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java b/guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java new file mode 100644 index 0000000000..c4b17b57d2 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java @@ -0,0 +1,57 @@ + +package com.baeldung.examples.guice; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import java.util.Date; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +/** + * + * @author Baeldung + */ +public class Communication { + + final Date start = new Date(); + + @Inject + private Logger logger; + + private Queue messageLog; + + @Named("CommsUUID") + private String commsID; + + @Inject + private DefaultCommunicator communicator; + + public Communication(Boolean keepRecords) { + if (keepRecords) { + messageLog = new LinkedList(); + } + } + + public boolean sendMessage(String message) { + if (!message.isEmpty() && messageLog != null) { + messageLog.add(message); + } + return communicator.sendMessage(message); + } + + public void print() { + if (messageLog != null) { + for (String message : messageLog) { + logger.info(message); + } + } else { + logger.info("Message logging wasn't enabled"); + } + } + + public DefaultCommunicator getCommunicator() { + return this.communicator; + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java b/guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java new file mode 100644 index 0000000000..444b775478 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java @@ -0,0 +1,12 @@ + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.constant.CommunicationModel; + +public interface CommunicationMode { + + public CommunicationModel getMode(); + + public boolean sendMessage(String message); + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java b/guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java new file mode 100644 index 0000000000..423c24f789 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java @@ -0,0 +1,48 @@ + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.marker.Communicator; +import com.google.inject.Inject; +import com.google.inject.name.Named; + + +public class DefaultCommunicator implements Communicator { + + private CommunicationMode defaultCommsMode; + @Inject + @Named("SMSComms") + CommunicationMode smsCommsMode; + @Inject + @Named("EmailComms") + CommunicationMode emailCommsMode; + @Inject + @Named("IMComms") + CommunicationMode imCommsMode; + + protected DefaultCommunicator(CommunicationMode defaultComms) { + this.defaultCommsMode = defaultComms; + } + + public DefaultCommunicator() { + + } + + public boolean sendMessage(String message) { + boolean sent = false; + if (defaultCommsMode != null) { + sent = sendMessageByDefault(message); + } else { + sent = smsCommsMode.sendMessage(message); + } + return sent; + } + + private boolean sendMessageByDefault(String message) { + boolean sent = false; + if (message != null && !message.trim().equals("")) { + return defaultCommsMode.sendMessage(message); + } + return sent; + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java b/guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java new file mode 100644 index 0000000000..642ee7ace0 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java @@ -0,0 +1,23 @@ +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; + +/** + * + * @author Baekdung + */ +public class EmailCommunicationMode implements CommunicationMode { + + @Override + public CommunicationModel getMode() { + return CommunicationModel.EMAIL; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String Message) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java b/guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java new file mode 100644 index 0000000000..9f34e9a241 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java @@ -0,0 +1,30 @@ + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; +import com.google.inject.Inject; +import java.util.logging.Logger; + +/** + * + * @author Baeldung + */ +public class IMCommunicationMode implements CommunicationMode { + + @Inject + private Logger logger; + + @Override + public CommunicationModel getMode() { + return CommunicationModel.IM; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String message) { + logger.info("IM Message Sent"); + return true; + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java b/guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java new file mode 100644 index 0000000000..251e249971 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java @@ -0,0 +1,29 @@ +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; +import com.google.inject.Inject; +import java.util.logging.Logger; + +/** + * + * @author Baeldung + */ +public class SMSCommunicationMode implements CommunicationMode { + + @Inject + private Logger logger; + + @Override + public CommunicationModel getMode() { + return CommunicationModel.SMS; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String message) { + logger.info("SMS message sent"); + return true; + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java b/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java new file mode 100644 index 0000000000..8926dfa714 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java @@ -0,0 +1,22 @@ +package com.baeldung.examples.guice.aop; + +import java.util.logging.Logger; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * + * @author Baeldung + */ +public class MessageLogger implements MethodInterceptor { + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + Object[] objectArray = invocation.getArguments(); + int i = 0; + for (Object object : objectArray) { + Logger.getAnonymousLogger().info("Sending message: " + object.toString()); + } + return invocation.proceed(); + } +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java b/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java new file mode 100644 index 0000000000..cacf3bde7c --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java @@ -0,0 +1,16 @@ +package com.baeldung.examples.guice.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Baeldung + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MessageSentLoggable { + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java b/guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java new file mode 100644 index 0000000000..dc9d258efa --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java @@ -0,0 +1,22 @@ +package com.baeldung.examples.guice.binding; + +import com.baeldung.examples.guice.aop.MessageLogger; +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.google.inject.AbstractModule; +import com.google.inject.matcher.Matchers; + +/** + * + * @author Baeldung + */ +public class AOPModule extends AbstractModule { + + @Override + protected void configure() { + bindInterceptor(Matchers.any(), + Matchers.annotatedWith(MessageSentLoggable.class), + new MessageLogger() + ); + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java b/guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java new file mode 100644 index 0000000000..9168195130 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java @@ -0,0 +1,36 @@ +package com.baeldung.examples.guice.binding; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.CommunicationMode; +import com.baeldung.examples.guice.DefaultCommunicator; +import com.baeldung.examples.guice.EmailCommunicationMode; +import com.baeldung.examples.guice.IMCommunicationMode; +import com.baeldung.examples.guice.SMSCommunicationMode; +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Baeldung + */ +public class BasicModule extends AbstractModule { + + @Override + protected void configure() { + try { + bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.TYPE)); + } catch (NoSuchMethodException ex) { + Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } + bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); + + bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); + } + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java b/guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java new file mode 100644 index 0000000000..b9fa604a32 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java @@ -0,0 +1,16 @@ +package com.baeldung.examples.guice.constant; + +/** + * + * @author Baeldung + */ +public enum CommunicationModel { + + EMAIL("Email"), SMS("SMS"), IM("IM"), PHONE("Phone"); + + final String name; + + CommunicationModel(String name) { + this.name = name; + } +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java b/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java new file mode 100644 index 0000000000..239666b6ab --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java @@ -0,0 +1,11 @@ +package com.baeldung.examples.guice.marker; + +/** + * + * @author Baeldung + */ +public interface Communicator { + + public boolean sendMessage(String message); + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java b/guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java new file mode 100644 index 0000000000..47b3e2e573 --- /dev/null +++ b/guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java @@ -0,0 +1,37 @@ +package com.baeldung.examples.guice.modules; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.CommunicationMode; +import com.baeldung.examples.guice.DefaultCommunicator; +import com.baeldung.examples.guice.EmailCommunicationMode; +import com.baeldung.examples.guice.IMCommunicationMode; +import com.baeldung.examples.guice.SMSCommunicationMode; +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Baeldung + */ +public class BasicModule extends AbstractModule { + + @Override + protected void configure() { + try { + bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.class)); + bind(Boolean.class).toInstance(true); + } catch (NoSuchMethodException ex) { + Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } + bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); + + bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); + } + +} From bca902362a131c0e00480cb1ddb0eb5dca526f03 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Thu, 2 Mar 2017 22:52:52 -0600 Subject: [PATCH 028/291] BAEL-393: adding guice-intro module to main pom (#1287) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index b0156a4289..d859f529da 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ guava guava18 guava19 + guice-intro disruptor handling-spring-static-resources From f57a7ddaed01142142c791f3dca9314081baf028 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Fri, 3 Mar 2017 06:15:34 +0100 Subject: [PATCH 029/291] Bael 641 (#1282) * BEEL-641 guava reflection utils code * BEEL-641 fix formatting * BEEL-641 add assertion on subttype number -> integer * BEEL-641 rename class * BEEL-641 formatting * BEEL-641 add comparison using standard java reflecetion api and guava one --- .../guava/GuavaReflectionUtilsTest.java | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 guava/src/test/java/org/baeldung/guava/GuavaReflectionUtilsTest.java diff --git a/guava/src/test/java/org/baeldung/guava/GuavaReflectionUtilsTest.java b/guava/src/test/java/org/baeldung/guava/GuavaReflectionUtilsTest.java new file mode 100644 index 0000000000..e59a682e08 --- /dev/null +++ b/guava/src/test/java/org/baeldung/guava/GuavaReflectionUtilsTest.java @@ -0,0 +1,150 @@ +package org.baeldung.guava; + + +import com.google.common.collect.Lists; +import com.google.common.reflect.Invokable; +import com.google.common.reflect.TypeToken; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GuavaReflectionUtilsTest { + + @Test + public void givenTwoGenericList_whenCheckIsAssignableFrom_thenReturnTrueDueToTypeErasure() { + //given + ArrayList stringList = Lists.newArrayList(); + ArrayList intList = Lists.newArrayList(); + + //when + boolean result = stringList.getClass().isAssignableFrom(intList.getClass()); + + //then + assertTrue(result); + } + + @Test + public void givenTypeToken_whenResolveType_thenShouldResolveProperType() { + //given + TypeToken> stringListToken = new TypeToken>() { + }; + TypeToken> integerListToken = new TypeToken>() { + }; + TypeToken> numberTypeToken = new TypeToken>() { + }; + + //then + assertFalse(stringListToken.isSubtypeOf(integerListToken)); + assertFalse(numberTypeToken.isSubtypeOf(integerListToken)); + assertTrue(integerListToken.isSubtypeOf(numberTypeToken)); + } + + @Test + public void givenCustomClass_whenCaptureGeneric_thenReturnTypeAtRuntime() { + //given + ParametrizedClass parametrizedClass = new ParametrizedClass() { + }; + + //then + assertEquals(parametrizedClass.type, TypeToken.of(String.class)); + } + + @Test + public void givenComplexType_whenGetTypeArgument_thenShouldReturnTypeAtRuntime() { + //given + TypeToken> funToken = new TypeToken>() { + }; + + //when + TypeToken funResultToken = funToken.resolveType(Function.class.getTypeParameters()[1]); + + //then + assertEquals(funResultToken, TypeToken.of(String.class)); + } + + + @Test + public void givenMapType_whenGetTypeArgumentOfEntry_thenShouldReturnTypeAtRuntime() throws NoSuchMethodException { + //given + TypeToken> mapToken = new TypeToken>() { + }; + + //when + TypeToken entrySetToken = mapToken.resolveType(Map.class.getMethod("entrySet").getGenericReturnType()); + + //then + assertEquals(entrySetToken, new TypeToken>>() { + }); + } + + @Test + public void givenInvokable_whenCheckPublicMethod_shouldReturnTrue() throws NoSuchMethodException { + //given + Method method = CustomClass.class.getMethod("somePublicMethod"); + Invokable invokable = new TypeToken() { + }.method(method); + + //when + boolean isPublicStandradJava = Modifier.isPublic(method.getModifiers()); + boolean isPublicGuava = invokable.isPublic(); + //then + assertTrue(isPublicStandradJava); + assertTrue(isPublicGuava); + } + + @Test + public void givenInvokable_whenCheckFinalMethod_shouldReturnFalseForIsOverridable() throws NoSuchMethodException { + //given + Method method = CustomClass.class.getMethod("notOverridablePublicMethod"); + Invokable invokable = new TypeToken() { + }.method(method); + + //when + boolean isOverridableStandardJava = (!(Modifier.isFinal(method.getModifiers()) || Modifier.isPrivate(method.getModifiers()) + || Modifier.isStatic(method.getModifiers()) + || Modifier.isFinal(method.getDeclaringClass().getModifiers()))); + boolean isOverridableFinalGauava = invokable.isOverridable(); + + //then + assertFalse(isOverridableStandardJava); + assertFalse(isOverridableFinalGauava); + } + + @Test + public void givenListOfType_whenGetReturnRype_shouldCaptureTypeAtRuntime() throws NoSuchMethodException { + //given + Method getMethod = List.class.getMethod("get", int.class); + + //when + Invokable, ?> invokable = new TypeToken>() { + }.method(getMethod); + + //then + assertEquals(TypeToken.of(Integer.class), invokable.getReturnType()); // Not Object.class! + } + + + abstract class ParametrizedClass { + TypeToken type = new TypeToken(getClass()) { + }; + } + + class CustomClass { + public void somePublicMethod() { + } + + public final void notOverridablePublicMethod() { + + } + } +} From 735b377a1a078f774b26f475954669ede2f203ac Mon Sep 17 00:00:00 2001 From: pedja4 Date: Fri, 3 Mar 2017 06:51:23 +0100 Subject: [PATCH 030/291] Update pom.xml --- reactor-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index 2be8892983..3aeb4af3d5 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -50,7 +50,7 @@ - 3.0.4.RELEASE + 3.0.5.RELEASE 4.12 3.6.1 1.1.3 From 8ffc21e8cf42bcbd4e9dfaa7111d955159cfad1d Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Fri, 3 Mar 2017 06:57:03 +0100 Subject: [PATCH 031/291] BAEL - 606 - Tests for JSR 354 Money implementation --- .../com/baeldung/money/JavaMoneyTest.java | 69 ++++++++----------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index ed737c6184..7ef4dceccb 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -1,13 +1,9 @@ package com.baeldung.money; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.math.BigDecimal; -import java.util.Locale; +import org.javamoney.moneta.FastMoney; +import org.javamoney.moneta.Money; +import org.javamoney.moneta.format.CurrencyStyle; +import org.junit.Test; import javax.money.CurrencyUnit; import javax.money.Monetary; @@ -19,43 +15,36 @@ import javax.money.convert.MonetaryConversions; import javax.money.format.AmountFormatQueryBuilder; import javax.money.format.MonetaryAmountFormat; import javax.money.format.MonetaryFormats; +import java.util.Locale; -import org.javamoney.moneta.FastMoney; -import org.javamoney.moneta.Money; -import org.javamoney.moneta.format.CurrencyStyle; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.junit.Assert.*; public class JavaMoneyTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); @Test public void givenCurrencyCode_whenString_thanExist() { - CurrencyUnit USD = Monetary.getCurrency("USD"); - assertNotNull(USD); - assertEquals(USD.getCurrencyCode(), "USD"); - assertEquals(USD.getNumericCode(), 840); - assertEquals(USD.getDefaultFractionDigits(), 2); + CurrencyUnit usd = Monetary.getCurrency("USD"); + + assertNotNull(usd); + assertEquals(usd.getCurrencyCode(), "USD"); + assertEquals(usd.getNumericCode(), 840); + assertEquals(usd.getDefaultFractionDigits(), 2); assertFalse(Monetary.isCurrencyAvailable("AAA")); - } - @Test + @Test(expected = UnknownCurrencyException.class) public void givenCurrencyCode_whenNoExist_thanThrowsError() { - thrown.expect(UnknownCurrencyException.class); - CurrencyUnit AAA = Monetary.getCurrency("AAA"); - assertNull(AAA); - throw new UnknownCurrencyException("AAA"); + CurrencyUnit aaa = Monetary.getCurrency("AAA"); + fail(); // if no exception } @Test - public void givenAmounts_whenStrinfied_thanEquals() { + public void givenAmounts_whenStringified_thanEquals() { CurrencyUnit USD = Monetary.getCurrency("USD"); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + Money moneyof = Money.of(12, USD); FastMoney fastmoneyof = FastMoney.of(2, USD); Money oneEuro = Money.of(1, "EUR"); @@ -67,30 +56,26 @@ public class JavaMoneyTest { assertEquals("EUR 1.30473908", fstAmtEUR.toString()); assertEquals("USD 12", moneyof.toString()); assertEquals("USD 2.00000", fastmoneyof.toString()); - } @Test public void givenCurrencies_whenCompared_thanNotequal() { MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); Money oneEuro = Money.of(1, "EUR"); + assertFalse(oneEuro.equals(FastMoney.of(1, "EUR"))); assertTrue(oneDolar.equals(Money.of(1, "USD"))); - } - @Test + @Test(expected = ArithmeticException.class) public void givenAmount_whenDivided_thanThrowsException() { MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); - thrown.expect(ArithmeticException.class); - MonetaryAmount oneDivThree = oneDolar.divide(3); - assertNull(oneDivThree); - throw new ArithmeticException(); - + oneDolar.divide(3); + fail(); // if no exception } @Test - public void givenArithmetic_whenStrinfied_thanEqualsAmount() { + public void givenArithmetic_whenStringified_thanEqualsAmount() { CurrencyUnit USD = Monetary.getCurrency("USD"); Money moneyof = Money.of(12, USD); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); @@ -100,11 +85,11 @@ public class JavaMoneyTest { MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); MonetaryAmount divideAmount = oneDolar.divide(0.25); - - MonetaryAmount[] monetaryAmounts = new MonetaryAmount[] { + + MonetaryAmount[] monetaryAmounts = new MonetaryAmount[]{ Money.of(100, "CHF"), Money.of(10.20, "CHF"), - Money.of(1.15, "CHF"), }; + Money.of(1.15, "CHF"),}; Money sumAmtCHF = Money.of(0, "CHF"); @@ -158,12 +143,12 @@ public class JavaMoneyTest { CurrencyConversion conversionUSD = MonetaryConversions.getConversion("USD"); CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR"); - + MonetaryAmount convertedAmountEURtoUSD = fstAmtEUR.with(conversionUSD); MonetaryAmount convertedAmountEURtoUSD2 = fstAmtEUR.with(convUSD); MonetaryAmount convertedAmountUSDtoEUR = oneDolar.with(conversionEUR); MonetaryAmount convertedAmountUSDtoEUR2 = oneDolar.with(convEUR); - + assertEquals("USD", USD.toString()); assertEquals("USD 1", oneDolar.toString()); assertEquals("EUR 1.30473908", fstAmtEUR.toString()); From 2538f131768f3ceb0978e8cd24aa59537610cfe6 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Fri, 3 Mar 2017 08:32:46 +0100 Subject: [PATCH 032/291] Mockito2 Java8 refactor --- .../ArgumentMatcherWithoutLambdaUnitTest.java | 26 ++++++++----------- .../java8/CustomAnswerWithLambdaUnitTest.java | 21 ++++++++------- .../CustomAnswerWithoutLambdaUnitTest.java | 23 ++++++++-------- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java index f4e8fb4cf5..786062ee57 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java @@ -1,21 +1,18 @@ package com.baeldung.mockito.java8; +import org.junit.Before; +import org.junit.Test; +import org.mockito.*; + +import java.util.Optional; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; -import java.util.Optional; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentMatchers; -import org.mockito.InjectMocks; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - public class ArgumentMatcherWithoutLambdaUnitTest { + @InjectMocks private UnemploymentServiceImpl unemploymentService; @@ -38,13 +35,12 @@ public class ArgumentMatcherWithoutLambdaUnitTest { } private class PeterArgumentMatcher implements ArgumentMatcher { + @Override public boolean matches(Person p) { - - if (p.getName().equals("Peter")) { - return true; - } - return false; + return p + .getName() + .equals("Peter"); } } diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java index b4e5abdc6c..06e9bca6d3 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithLambdaUnitTest.java @@ -1,19 +1,20 @@ package com.baeldung.mockito.java8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import java.util.stream.Stream; - import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + public class CustomAnswerWithLambdaUnitTest { + @InjectMocks private UnemploymentServiceImpl unemploymentService; @@ -38,8 +39,8 @@ public class CustomAnswerWithLambdaUnitTest { public void init() { MockitoAnnotations.initMocks(this); - when(jobService.listJobs(any(Person.class))).then((i) -> { - return ((Person) i.getArgument(0)).getName().equals("Peter") ? Stream.of(new JobPosition("Teacher")) : Stream.empty(); - }); + when(jobService.listJobs(any(Person.class))).then((i) -> + Stream.of(new JobPosition("Teacher")) + .filter(p -> ((Person) i.getArgument(0)).getName().equals("Peter"))); } } diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java index 28922bb303..9d1aa3a3c0 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java @@ -1,12 +1,5 @@ package com.baeldung.mockito.java8; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import java.util.stream.Stream; - import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; @@ -15,8 +8,16 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + public class CustomAnswerWithoutLambdaUnitTest { + @InjectMocks private UnemploymentServiceImpl unemploymentService; @@ -38,15 +39,13 @@ public class CustomAnswerWithoutLambdaUnitTest { } private class PersonAnswer implements Answer> { + @Override public Stream answer(InvocationOnMock invocation) throws Throwable { Person person = invocation.getArgument(0); - if(person.getName().equals("Peter")) { - return Stream.builder().add(new JobPosition("Teacher")).build(); - } - - return Stream.empty(); + return Stream.of(new JobPosition("Teacher")) + .filter(p -> person.getName().equals("Peter")); } } From 005ac52b68ffb3ecdc02b907e9d0541dd7527d7d Mon Sep 17 00:00:00 2001 From: mariiakulik Date: Fri, 3 Mar 2017 20:19:26 +0100 Subject: [PATCH 033/291] Create README.md --- spring-security-cache-control/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 spring-security-cache-control/README.md diff --git a/spring-security-cache-control/README.md b/spring-security-cache-control/README.md new file mode 100644 index 0000000000..4b0bab72cb --- /dev/null +++ b/spring-security-cache-control/README.md @@ -0,0 +1,6 @@ +========= + +## Spring Security Cache Control + +### Relevant Articles: +- [Spring Security – Cache Control Headers](http://www.baeldung.com/spring-security-cache-control-headers) From 10a648dfbcbe6ab1ee107cad4eb617039c991bd3 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Sat, 4 Mar 2017 11:05:43 +0100 Subject: [PATCH 034/291] BAEL - 606 - Test improvements --- .../com/baeldung/money/JavaMoneyTest.java | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index 7ef4dceccb..3d2f986c30 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -29,31 +29,23 @@ public class JavaMoneyTest { assertEquals(usd.getCurrencyCode(), "USD"); assertEquals(usd.getNumericCode(), 840); assertEquals(usd.getDefaultFractionDigits(), 2); - assertFalse(Monetary.isCurrencyAvailable("AAA")); } @Test(expected = UnknownCurrencyException.class) public void givenCurrencyCode_whenNoExist_thanThrowsError() { - CurrencyUnit aaa = Monetary.getCurrency("AAA"); + Monetary.getCurrency("AAA"); fail(); // if no exception } @Test public void givenAmounts_whenStringified_thanEquals() { - CurrencyUnit USD = Monetary.getCurrency("USD"); - MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); - MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + CurrencyUnit usd = Monetary.getCurrency("USD"); + MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(usd).setNumber(200).create(); + Money moneyof = Money.of(12, usd); + FastMoney fastmoneyof = FastMoney.of(2, usd); - Money moneyof = Money.of(12, USD); - FastMoney fastmoneyof = FastMoney.of(2, USD); - Money oneEuro = Money.of(1, "EUR"); - - assertEquals("USD", USD.toString()); - assertEquals("USD 1", oneDolar.toString()); - assertEquals("EUR 1", oneEuro.toString()); - assertEquals("USD 200.5", fstAmtUSD.toString()); - assertEquals("EUR 1.30473908", fstAmtEUR.toString()); + assertEquals("USD", usd.toString()); + assertEquals("USD 200", fstAmtUSD.toString()); assertEquals("USD 12", moneyof.toString()); assertEquals("USD 2.00000", fastmoneyof.toString()); } @@ -75,35 +67,34 @@ public class JavaMoneyTest { } @Test - public void givenArithmetic_whenStringified_thanEqualsAmount() { - CurrencyUnit USD = Monetary.getCurrency("USD"); - Money moneyof = Money.of(12, USD); - MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(USD).setNumber(200.50).create(); - Money calcAmtUSD = Money.of(1, "USD").subtract(fstAmtUSD); - FastMoney fastmoneyof = FastMoney.of(2, USD); - MonetaryAmount calcMoneyFastMoney = moneyof.subtract(fastmoneyof); - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); - MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); - MonetaryAmount divideAmount = oneDolar.divide(0.25); - + public void givenAmounts_whenSummed_thanCorrect() { MonetaryAmount[] monetaryAmounts = new MonetaryAmount[]{ - Money.of(100, "CHF"), - Money.of(10.20, "CHF"), - Money.of(1.15, "CHF"),}; + Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF")}; Money sumAmtCHF = Money.of(0, "CHF"); - for (MonetaryAmount monetaryAmount : monetaryAmounts) { sumAmtCHF = sumAmtCHF.add(monetaryAmount); } - assertEquals("USD", USD.toString()); + + assertEquals("CHF 111.35", sumAmtCHF.toString()); + } + + @Test + public void givenArithmetic_whenStringified_thanEqualsAmount() { + CurrencyUnit usd = Monetary.getCurrency("USD"); + + Money moneyof = Money.of(12, usd); + MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(usd).setNumber(200.50).create(); + MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + Money subtractedAmount = Money.of(1, "USD").subtract(fstAmtUSD); + MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); + MonetaryAmount divideAmount = oneDolar.divide(0.25); + + assertEquals("USD", usd.toString()); assertEquals("USD 1", oneDolar.toString()); assertEquals("USD 200.5", fstAmtUSD.toString()); assertEquals("USD 12", moneyof.toString()); - assertEquals("USD 2.00000", fastmoneyof.toString()); - assertEquals("USD -199.5", calcAmtUSD.toString()); - assertEquals("CHF 111.35", sumAmtCHF.toString()); - assertEquals("USD 10", calcMoneyFastMoney.toString()); + assertEquals("USD -199.5", subtractedAmount.toString()); assertEquals("USD 0.25", multiplyAmount.toString()); assertEquals("USD 4", divideAmount.toString()); } From e9d847186dd08b04b55553d23336c4d2c67cfa17 Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Sat, 4 Mar 2017 16:57:28 +0200 Subject: [PATCH 035/291] add rest-assured test (#1292) --- .../spring-cloud-bootstrap/gateway/pom.xml | 7 + .../cloud/bootstrap/gateway/LiveTest.java | 198 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml index 97c440c249..13ae6b4050 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml @@ -51,6 +51,13 @@ spring-boot-starter-test test
+ + + io.rest-assured + rest-assured + test + 3.0.2 + diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java new file mode 100644 index 0000000000..71ed2cd709 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java @@ -0,0 +1,198 @@ +package com.baeldung.spring.cloud.bootstrap.gateway; + +import static io.restassured.RestAssured.config; +import io.restassured.RestAssured; +import io.restassured.authentication.FormAuthConfig; +import io.restassured.config.RedirectConfig; +import io.restassured.http.ContentType; +import io.restassured.response.Response; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpStatus; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +public class LiveTest { + + private final String ROOT_URI = "http://localhost:8080"; + private final FormAuthConfig formConfig = new FormAuthConfig("/login", "username", "password"); + + @Before + public void setup() { + RestAssured.config = config().redirect(RedirectConfig.redirectConfig() + .followRedirects(false)); + } + + @Test + public void whenGetAllBooks_thenSuccess() { + final Response response = RestAssured.get(ROOT_URI + "/book-service/books"); + Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + } + + @Test + public void whenAccessProtectedResourceWithoutLogin_thenRedirectToLogin() { + final Response response = RestAssured.get(ROOT_URI + "/book-service/books/1"); + Assert.assertEquals(HttpStatus.FOUND.value(), response.getStatusCode()); + Assert.assertEquals("http://localhost:8080/login", response.getHeader("Location")); + } + + @Test + public void whenAccessProtectedResourceAfterLogin_thenSuccess() { + final Response response = RestAssured.given() + .auth() + .form("user", "password", formConfig) + .get(ROOT_URI + "/book-service/books/1"); + Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + } + + @Test + public void whenAccessAdminProtectedResource_thenForbidden() { + final Response response = RestAssured.given() + .auth() + .form("user", "password", formConfig) + .get(ROOT_URI + "/rating-service/ratings"); + Assert.assertEquals(HttpStatus.FORBIDDEN.value(), response.getStatusCode()); + + } + + @Test + public void whenAdminAccessProtectedResource_thenSuccess() { + final Response response = RestAssured.given() + .auth() + .form("admin", "admin", formConfig) + .get(ROOT_URI + "/rating-service/ratings"); + Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + } + + @Test + public void whenAdminAccessDiscoveryResource_thenSuccess() { + final Response response = RestAssured.given() + .auth() + .form("admin", "admin", formConfig) + .get(ROOT_URI + "/discovery"); + Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode()); + } + + @Test + public void whenAddnewRating_thenSuccess() { + + final Rating rating = new Rating(1L, 4); + + // request the protected resource + final Response ratingResponse = RestAssured.given() + .auth() + .form("admin", "admin", formConfig) + .and() + .contentType(ContentType.JSON) + .body(rating) + .post(ROOT_URI + "/rating-service/ratings"); + final Rating result = ratingResponse.as(Rating.class); + Assert.assertEquals(HttpStatus.OK.value(), ratingResponse.getStatusCode()); + Assert.assertEquals(rating.getBookId(), result.getBookId()); + Assert.assertEquals(rating.getStars(), result.getStars()); + } + + @Test + public void whenAddnewBook_thenSuccess() { + final Book book = new Book("Baeldung", "How to spring cloud"); + + // request the protected resource + final Response bookResponse = RestAssured.given() + .auth() + .form("admin", "admin", formConfig) + .and() + .contentType(ContentType.JSON) + .body(book) + .post(ROOT_URI + "/book-service/books"); + final Book result = bookResponse.as(Book.class); + Assert.assertEquals(HttpStatus.OK.value(), bookResponse.getStatusCode()); + Assert.assertEquals(book.getAuthor(), result.getAuthor()); + Assert.assertEquals(book.getTitle(), result.getTitle()); + + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Book { + + private Long id; + private String author; + private String title; + + public Book() { + } + + public Book(String author, String title) { + this.author = author; + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Rating { + private Long id; + private Long bookId; + private int stars; + + public Rating() { + } + + public Rating(Long bookId, int stars) { + this.bookId = bookId; + this.stars = stars; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getBookId() { + return bookId; + } + + public void setBookId(Long bookId) { + this.bookId = bookId; + } + + public int getStars() { + return stars; + } + + public void setStars(int stars) { + this.stars = stars; + } + } + +} \ No newline at end of file From 15eb03d21241e07b58de487a8dac2a4e20bb10d1 Mon Sep 17 00:00:00 2001 From: eugenp Date: Sat, 4 Mar 2017 17:52:50 +0200 Subject: [PATCH 036/291] minor cleanup --- core-java/0.004102810554955205 | 0 core-java/0.04832801936270381 | 0 core-java/0.5633433244738808 | 0 core-java/0.5967303215007616 | 0 core-java/0.6256429734439612 | 0 core-java/0.9252611327674576 | 0 core-java/0.9799201796740292 | 0 7 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 core-java/0.004102810554955205 delete mode 100644 core-java/0.04832801936270381 delete mode 100644 core-java/0.5633433244738808 delete mode 100644 core-java/0.5967303215007616 delete mode 100644 core-java/0.6256429734439612 delete mode 100644 core-java/0.9252611327674576 delete mode 100644 core-java/0.9799201796740292 diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.5967303215007616 b/core-java/0.5967303215007616 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.9252611327674576 b/core-java/0.9252611327674576 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292 deleted file mode 100644 index e69de29bb2..0000000000 From 348adc878bf1a4ef4e99f16fbfb111ce75c5b4d0 Mon Sep 17 00:00:00 2001 From: Yasin Date: Sat, 4 Mar 2017 22:28:03 +0530 Subject: [PATCH 037/291] Fixed compilation error and removed unused import (#1298) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import --- .../test/java/com/baeldung/java9/Java9OptionalsStreamTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalsStreamTest.java b/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalsStreamTest.java index 121c17a860..a6060b1a9d 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalsStreamTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/Java9OptionalsStreamTest.java @@ -1,4 +1,4 @@ -package com.baeldung.java8; +package com.baeldung.java9; import static org.junit.Assert.assertEquals; @@ -8,7 +8,6 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Before; import org.junit.Test; public class Java9OptionalsStreamTest { From 28fe826e3b6495475eaf1c2c27f6b15d2c1f58e4 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Sun, 5 Mar 2017 07:29:47 +0100 Subject: [PATCH 038/291] BAEL-574 - Removing redundant pattern check --- .../cloud/bootstrap/svcbook/BookServiceApplication.java | 1 - .../spring/cloud/bootstrap/zipkin/ZipkinApplication.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index 63ff0fb134..3d55a59dbc 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -45,7 +45,6 @@ public class BookServiceApplication { delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); if (!span.name.matches(skipPattern)) delegate.report(span); } - if (!span.name.matches(skipPattern)) delegate.report(span); } }; } diff --git a/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java index bb1355e258..d757567156 100644 --- a/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java @@ -10,6 +10,6 @@ import zipkin.server.EnableZipkinServer; @EnableZipkinServer public class ZipkinApplication { public static void main(String[] args) { - SpringApplication.run(ZipkinApplication.class, args); - } + SpringApplication.run(ZipkinApplication.class, args); + } } From c83c449fa5a7ac2462fabf0ed26969f1b037aa12 Mon Sep 17 00:00:00 2001 From: Alex Vargas Date: Sun, 5 Mar 2017 02:09:37 -0800 Subject: [PATCH 039/291] Bael 389 - Chat-like app using the Java API for WebSocket (#1265) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces --- java-websocket/pom.xml | 41 ++++++ .../main/java/com/baeldung/model/Message.java | 36 +++++ .../com/baeldung/websocket/ChatEndpoint.java | 71 +++++++++ .../baeldung/websocket/MessageDecoder.java | 32 +++++ .../baeldung/websocket/MessageEncoder.java | 27 ++++ .../src/main/webapp/WEB-INF/beans.xml | 5 + .../src/main/webapp/WEB-INF/web.xml | 7 + java-websocket/src/main/webapp/index.html | 30 ++++ java-websocket/src/main/webapp/style.css | 136 ++++++++++++++++++ java-websocket/src/main/webapp/websocket.js | 23 +++ 10 files changed, 408 insertions(+) create mode 100644 java-websocket/pom.xml create mode 100644 java-websocket/src/main/java/com/baeldung/model/Message.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java create mode 100644 java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java create mode 100644 java-websocket/src/main/webapp/WEB-INF/beans.xml create mode 100644 java-websocket/src/main/webapp/WEB-INF/web.xml create mode 100644 java-websocket/src/main/webapp/index.html create mode 100644 java-websocket/src/main/webapp/style.css create mode 100644 java-websocket/src/main/webapp/websocket.js diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml new file mode 100644 index 0000000000..929e6491fd --- /dev/null +++ b/java-websocket/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + com.baeldung + java-websocket + war + 0.0.1-SNAPSHOT + java-websocket Maven Webapp + http://maven.apache.org + + + UTF-8 + + + + + javax.websocket + javax.websocket-api + 1.1 + + + com.google.code.gson + gson + 2.8.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + diff --git a/java-websocket/src/main/java/com/baeldung/model/Message.java b/java-websocket/src/main/java/com/baeldung/model/Message.java new file mode 100644 index 0000000000..3d5bbcbc5d --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/model/Message.java @@ -0,0 +1,36 @@ +package com.baeldung.model; + +public class Message { + private String from; + private String to; + private String content; + + @Override + public String toString() { + return super.toString(); + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java new file mode 100644 index 0000000000..c4e20f4b27 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/ChatEndpoint.java @@ -0,0 +1,71 @@ +package com.baeldung.websocket; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.websocket.EncodeException; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +import com.baeldung.model.Message; + +@ServerEndpoint(value = "/chat/{username}", decoders = MessageDecoder.class, encoders = MessageEncoder.class) +public class ChatEndpoint { + private Session session; + private static final Set chatEndpoints = new CopyOnWriteArraySet<>(); + private static HashMap users = new HashMap<>(); + + @OnOpen + public void onOpen(Session session, @PathParam("username") String username) throws IOException, EncodeException { + + this.session = session; + chatEndpoints.add(this); + users.put(session.getId(), username); + + Message message = new Message(); + message.setFrom(username); + message.setContent("Connected!"); + broadcast(message); + } + + @OnMessage + public void onMessage(Session session, Message message) throws IOException, EncodeException { + message.setFrom(users.get(session.getId())); + broadcast(message); + } + + @OnClose + public void onClose(Session session) throws IOException, EncodeException { + chatEndpoints.remove(this); + Message message = new Message(); + message.setFrom(users.get(session.getId())); + message.setContent("Disconnected!"); + broadcast(message); + } + + @OnError + public void onError(Session session, Throwable throwable) { + // Do error handling here + } + + private static void broadcast(Message message) throws IOException, EncodeException { + chatEndpoints.forEach(endpoint -> { + synchronized (endpoint) { + try { + endpoint.session.getBasicRemote() + .sendObject(message); + } catch (IOException | EncodeException e) { + e.printStackTrace(); + } + } + }); + } + +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java new file mode 100644 index 0000000000..29ae5b93e6 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java @@ -0,0 +1,32 @@ +package com.baeldung.websocket; + +import javax.websocket.DecodeException; +import javax.websocket.Decoder; +import javax.websocket.EndpointConfig; + +import com.baeldung.model.Message; +import com.google.gson.Gson; + +public class MessageDecoder implements Decoder.Text { + @Override + public Message decode(String s) throws DecodeException { + Gson gson = new Gson(); + Message message = gson.fromJson(s, Message.class); + return message; + } + + @Override + public boolean willDecode(String s) { + return (s != null); + } + + @Override + public void init(EndpointConfig endpointConfig) { + // Custom initialization logic + } + + @Override + public void destroy() { + // Close resources + } +} diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java new file mode 100644 index 0000000000..bfecc87a96 --- /dev/null +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java @@ -0,0 +1,27 @@ +package com.baeldung.websocket; + +import javax.websocket.EncodeException; +import javax.websocket.Encoder; +import javax.websocket.EndpointConfig; + +import com.baeldung.model.Message; +import com.google.gson.Gson; + +public class MessageEncoder implements Encoder.Text { + @Override + public String encode(Message message) throws EncodeException { + Gson gson = new Gson(); + String json = gson.toJson(message); + return json; + } + + @Override + public void init(EndpointConfig endpointConfig) { + // Custom initialization logic + } + + @Override + public void destroy() { + // Close resources + } +} diff --git a/java-websocket/src/main/webapp/WEB-INF/beans.xml b/java-websocket/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..73cd0d8e10 --- /dev/null +++ b/java-websocket/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/java-websocket/src/main/webapp/WEB-INF/web.xml b/java-websocket/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..9f88c1f963 --- /dev/null +++ b/java-websocket/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + + Archetype Created Web Application + diff --git a/java-websocket/src/main/webapp/index.html b/java-websocket/src/main/webapp/index.html new file mode 100644 index 0000000000..2b76fb1e49 --- /dev/null +++ b/java-websocket/src/main/webapp/index.html @@ -0,0 +1,30 @@ + + + Chat + + + + + + + + + + + + + +
+ + +
+ +
+ + +
+ + + + + \ No newline at end of file diff --git a/java-websocket/src/main/webapp/style.css b/java-websocket/src/main/webapp/style.css new file mode 100644 index 0000000000..ec0982005a --- /dev/null +++ b/java-websocket/src/main/webapp/style.css @@ -0,0 +1,136 @@ +body { + font-family: Arial, Helvetica, sans-serif; + font-size: 80%; + background-color: #1f1f1f; +} + +#wrapper { + width: 960px; + margin: auto; + text-align: left; + color: #d9d9d9; +} + +p { + text-align: left; +} + +.button { + display: inline; + color: #fff; + background-color: #f2791d; + padding: 8px; + margin: auto; + border-radius: 8px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + box-shadow: none; + border: none; +} + +.button:hover { + background-color: #ffb15e; +} +.button a, a:visited, a:hover, a:active { + color: #fff; + text-decoration: none; +} + +#addDevice { + text-align: center; + width: 960px; + margin: auto; + margin-bottom: 10px; +} + +#addDeviceForm { + text-align: left; + width: 400px; + margin: auto; + padding: 10px; +} + +#addDeviceForm span { + display: block; +} + +#content { + margin: auto; + width: 960px; +} + +.device { + width: 180px; + height: 110px; + margin: 10px; + padding: 16px; + color: #fff; + vertical-align: top; + border-radius: 8px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + display: inline-block; +} + +.device.off { + background-color: #c8cccf; +} + +.device span { + display: block; +} + +.deviceName { + text-align: center; + font-weight: bold; + margin-bottom: 12px; +} + +.removeDevice { + margin-top: 12px; + text-align: center; +} + +.device.Appliance { + background-color: #5eb85e; +} + +.device.Appliance a:hover { + color: #a1ed82; +} + +.device.Electronics { + background-color: #0f90d1; +} + +.device.Electronics a:hover { + color: #4badd1; +} + +.device.Lights { + background-color: #c2a00c; +} + +.device.Lights a:hover { + color: #fad232; +} + +.device.Other { + background-color: #db524d; +} + +.device.Other a:hover { + color: #ff907d; +} + +.device a { + text-decoration: none; +} + +.device a:visited, a:active, a:hover { + color: #fff; +} + +.device a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/java-websocket/src/main/webapp/websocket.js b/java-websocket/src/main/webapp/websocket.js new file mode 100644 index 0000000000..39e5687f0c --- /dev/null +++ b/java-websocket/src/main/webapp/websocket.js @@ -0,0 +1,23 @@ +var ws; + +function connect() { + var username = document.getElementById("username").value; + ws = new WebSocket("ws://" + document.location.host + "/java-websocket/chat/" + username); + + + ws.onmessage = function(event) { + var log = document.getElementById("log"); + console.log(event.data); + var message = JSON.parse(event.data); + log.innerHTML += message.from + " : " + message.content + "\n"; + }; +} + +function send() { + var content = document.getElementById("msg").value; + var json = JSON.stringify({ + "content":content + }); + + ws.send(json); +} \ No newline at end of file From 31b7ced8c4c96bbae3c1cabb12a9e0bfa821e40c Mon Sep 17 00:00:00 2001 From: nguyennamthai Date: Sun, 5 Mar 2017 17:19:42 +0700 Subject: [PATCH 040/291] Introduction to Apache Commons Lang 3 (#1301) --- apache-commons/pom.xml | 36 +++++ .../commons/lang3/ArrayUtilsTest.java | 137 ++++++++++++++++++ .../commons/lang3/StringUtilsTest.java | 99 +++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 apache-commons/pom.xml create mode 100644 apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java create mode 100644 apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java diff --git a/apache-commons/pom.xml b/apache-commons/pom.xml new file mode 100644 index 0000000000..6e5c2065db --- /dev/null +++ b/apache-commons/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + com.baeldung + apache-commons + 0.0.1-SNAPSHOT + + 4.12 + 3.6.0 + + + + + maven-compiler-plugin + ${compiler.version} + + 1.8 + 1.8 + + + + + + + org.apache.commons + commons-lang3 + 3.5 + + + junit + junit + ${junit.version} + test + + + \ No newline at end of file diff --git a/apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java b/apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java new file mode 100644 index 0000000000..b579458730 --- /dev/null +++ b/apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java @@ -0,0 +1,137 @@ +package com.baeldung.commons.lang3; + +import org.apache.commons.lang3.ArrayUtils; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; + +public class ArrayUtilsTest { + @Test + public void givenArray_whenAddingElementAtSpecifiedPosition_thenCorrect() { + int[] oldArray = { 2, 3, 4, 5 }; + int[] newArray = ArrayUtils.add(oldArray, 0, 1); + int[] expectedArray = { 1, 2, 3, 4, 5 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenAddingElementAtTheEnd_thenCorrect() { + int[] oldArray = { 2, 3, 4, 5 }; + int[] newArray = ArrayUtils.add(oldArray, 1); + int[] expectedArray = { 2, 3, 4, 5, 1 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenAddingAllElementsAtTheEnd_thenCorrect() { + int[] oldArray = { 0, 1, 2 }; + int[] newArray = ArrayUtils.addAll(oldArray, 3, 4, 5); + int[] expectedArray = { 0, 1, 2, 3, 4, 5 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenRemovingElementAtSpecifiedPosition_thenCorrect() { + int[] oldArray = { 1, 2, 3, 4, 5 }; + int[] newArray = ArrayUtils.remove(oldArray, 1); + int[] expectedArray = { 1, 3, 4, 5 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenRemovingAllElementsAtSpecifiedPositions_thenCorrect() { + int[] oldArray = { 1, 2, 3, 4, 5 }; + int[] newArray = ArrayUtils.removeAll(oldArray, 1, 3); + int[] expectedArray = { 1, 3, 5 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenRemovingAnElement_thenCorrect() { + int[] oldArray = { 1, 2, 3, 3, 4 }; + int[] newArray = ArrayUtils.removeElement(oldArray, 3); + int[] expectedArray = { 1, 2, 3, 4 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenRemovingElements_thenCorrect() { + int[] oldArray = { 1, 2, 3, 3, 4 }; + int[] newArray = ArrayUtils.removeElements(oldArray, 2, 3, 5); + int[] expectedArray = { 1, 3, 4 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenRemovingAllElementOccurences_thenCorrect() { + int[] oldArray = { 1, 2, 2, 2, 3 }; + int[] newArray = ArrayUtils.removeAllOccurences(oldArray, 2); + int[] expectedArray = { 1, 3 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenCheckingExistingElement_thenCorrect() { + int[] array = { 1, 3, 5, 7, 9 }; + boolean evenContained = ArrayUtils.contains(array, 2); + boolean oddContained = ArrayUtils.contains(array, 7); + assertEquals(false, evenContained); + assertEquals(true, oddContained); + } + + @Test + public void givenArray_whenReversingElementsWithinARange_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.reverse(originalArray, 1, 4); + int[] expectedArray = { 1, 4, 3, 2, 5 }; + assertArrayEquals(expectedArray, originalArray); + } + + @Test + public void givenArray_whenReversingAllElements_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.reverse(originalArray); + int[] expectedArray = { 5, 4, 3, 2, 1 }; + assertArrayEquals(expectedArray, originalArray); + } + + @Test + public void givenArray_whenShiftingElementsWithinARange_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.shift(originalArray, 1, 4, 1); + int[] expectedArray = { 1, 4, 2, 3, 5 }; + assertArrayEquals(expectedArray, originalArray); + } + + @Test + public void givenArray_whenShiftingAllElements_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.shift(originalArray, 1); + int[] expectedArray = { 5, 1, 2, 3, 4 }; + assertArrayEquals(expectedArray, originalArray); + } + + @Test + public void givenArray_whenExtractingElements_thenCorrect() { + int[] oldArray = { 1, 2, 3, 4, 5 }; + int[] newArray = ArrayUtils.subarray(oldArray, 2, 7); + int[] expectedArray = { 3, 4, 5 }; + assertArrayEquals(expectedArray, newArray); + } + + @Test + public void givenArray_whenSwapingElementsWithinARange_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.swap(originalArray, 0, 3, 2); + int[] expectedArray = { 4, 5, 3, 1, 2 }; + assertArrayEquals(expectedArray, originalArray); + } + + @Test + public void givenArray_whenSwapingElementsAtSpecifiedPositions_thenCorrect() { + int[] originalArray = { 1, 2, 3, 4, 5 }; + ArrayUtils.swap(originalArray, 0, 3); + int[] expectedArray = { 4, 2, 3, 1, 5 }; + assertArrayEquals(expectedArray, originalArray); + } +} diff --git a/apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java b/apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java new file mode 100644 index 0000000000..a17a8ea60d --- /dev/null +++ b/apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java @@ -0,0 +1,99 @@ +package com.baeldung.commons.lang3; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +public class StringUtilsTest { + @Test + public void givenString_whenCheckingContainsAny_thenCorrect() { + String string = "baeldung.com"; + boolean contained1 = StringUtils.containsAny(string, 'a', 'b', 'c'); + boolean contained2 = StringUtils.containsAny(string, 'x', 'y', 'z'); + boolean contained3 = StringUtils.containsAny(string, "abc"); + boolean contained4 = StringUtils.containsAny(string, "xyz"); + assertTrue(contained1); + assertFalse(contained2); + assertTrue(contained3); + assertFalse(contained4); + } + + @Test + public void givenString_whenCheckingContainsIgnoreCase_thenCorrect() { + String string = "baeldung.com"; + boolean contained = StringUtils.containsIgnoreCase(string, "BAELDUNG"); + assertTrue(contained); + } + + @Test + public void givenString_whenCountingMatches_thenCorrect() { + String string = "welcome to www.baeldung.com"; + int charNum = StringUtils.countMatches(string, 'w'); + int stringNum = StringUtils.countMatches(string, "com"); + assertEquals(4, charNum); + assertEquals(2, stringNum); + } + + @Test + public void givenString_whenAppendingAndPrependingIfMissing_thenCorrect() { + String string = "baeldung.com"; + String stringWithSuffix = StringUtils.appendIfMissing(string, ".com"); + String stringWithPrefix = StringUtils.prependIfMissing(string, "www."); + assertEquals("baeldung.com", stringWithSuffix); + assertEquals("www.baeldung.com", stringWithPrefix); + } + + @Test + public void givenString_whenSwappingCase_thenCorrect() { + String originalString = "baeldung.COM"; + String swappedString = StringUtils.swapCase(originalString); + assertEquals("BAELDUNG.com", swappedString); + } + + @Test + public void givenString_whenCapitalizing_thenCorrect() { + String originalString = "baeldung"; + String capitalizedString = StringUtils.capitalize(originalString); + assertEquals("Baeldung", capitalizedString); + } + + @Test + public void givenString_whenUncapitalizing_thenCorrect() { + String originalString = "Baeldung"; + String uncapitalizedString = StringUtils.uncapitalize(originalString); + assertEquals("baeldung", uncapitalizedString); + } + + @Test + public void givenString_whenReversingCharacters_thenCorrect() { + String originalString = "baeldung"; + String reversedString = StringUtils.reverse(originalString); + assertEquals("gnudleab", reversedString); + } + + @Test + public void givenString_whenReversingWithDelimiter_thenCorrect() { + String originalString = "www.baeldung.com"; + String reversedString = StringUtils.reverseDelimited(originalString, '.'); + assertEquals("com.baeldung.www", reversedString); + } + + @Test + public void givenString_whenRotatingTwoPositions_thenCorrect() { + String originalString = "baeldung"; + String rotatedString = StringUtils.rotate(originalString, 4); + assertEquals("dungbael", rotatedString); + } + + @Test + public void givenTwoStrings_whenComparing_thenCorrect() { + String tutorials = "Baeldung Tutorials"; + String courses = "Baeldung Courses"; + String diff1 = StringUtils.difference(tutorials, courses); + String diff2 = StringUtils.difference(courses, tutorials); + assertEquals("Courses", diff1); + assertEquals("Tutorials", diff2); + } +} From b9314b142c4adebefafec463fc0850e892816899 Mon Sep 17 00:00:00 2001 From: Paulo Motta Date: Sun, 5 Mar 2017 08:48:22 -0300 Subject: [PATCH 041/291] Create PrimitiveConversionsJUnitTest.java Tests for the possible conversions for primitive data types --- .../PrimitiveConversionsJUnitTest.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java diff --git a/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java b/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java new file mode 100644 index 0000000000..4137b5af00 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java @@ -0,0 +1,125 @@ +package com.baeldung.primitiveconversions; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author paulo.motta + */ +public class PrimitiveConversionsJUnitTest { + + @Test + public void givenDataWithLessBits_whenAttributingToLargerSizeVariable_thenNoSpecialNotation() { + int myInt = 127; + + long myLong = myInt; + assertEquals(127L, myLong); + + float myFloat = myLong; + assertEquals(127.0f, myFloat, 0.00001f); + + double myDouble = myLong; + assertEquals(127.0, myDouble,0.00001); + } + + @Test + public void givenDataWithMoreBits_whenAttributingToSmallerSizeVariable_thenCastOperatorNeeded() { + + long myLong = 127L; + double myDouble = 127.0; + + float myFloat = (float) myDouble; + assertEquals(127.0f, myFloat, 0.00001f); + + int myInt = (int) myLong; + assertEquals(127, myInt); + + byte myByte = (byte) myInt; + assertEquals( ((byte)127), myByte); + } + + @Test + public void givenPrimitiveData_whenAssiginingToWrapper_thenAutomaticBoxingHappens(){ + int myInt = 127; + + Integer myIntegerReference = myInt; + assertEquals(new Integer("127"), myIntegerReference); + + } + + @Test + public void givenWrapperObjectData_whenAssiginingToPrimitive_thenAutomaticUnboxingHappens(){ + Integer myIntegerReference = new Integer("127"); + + int myOtherInt = myIntegerReference; + assertEquals(127, myOtherInt); + + } + + @Test + public void givenByteValue_whenConvertingToChar_thenWidenAndNarrowTakesPlace(){ + byte myLargeValueByte = (byte) 130; //0b10000010 + System.out.println(myLargeValueByte); //0b10000010 -126 + assertEquals( -126, myLargeValueByte); + + int myLargeValueInt = myLargeValueByte; + System.out.println(myLargeValueInt); //0b11111111 11111111 11111111 10000010 -126 + assertEquals( -126, myLargeValueInt); + + char myLargeValueChar = (char) myLargeValueByte; + System.out.println(myLargeValueChar);//0b11111111 10000010 unsigned 0xFF82 + assertEquals(0xFF82, myLargeValueChar); + + myLargeValueInt = myLargeValueChar; + System.out.println(myLargeValueInt); //0b11111111 10000010 65410 + assertEquals(65410, myLargeValueInt); + + byte myOtherByte = (byte) myLargeValueInt; + System.out.println(myOtherByte); //0b10000010 -126 + assertEquals( -126, myOtherByte); + + + char myLargeValueChar2 = 130; //This is an int not a byte! + System.out.println(myLargeValueChar2);//0b00000000 10000010 unsigned 0x0082 + assertEquals(0x0082, myLargeValueChar2); + + int myLargeValueInt2 = myLargeValueChar2; + System.out.println(myLargeValueInt2); //0b00000000 10000010 130 + assertEquals(130, myLargeValueInt2); + + byte myOtherByte2 = (byte) myLargeValueInt2; + System.out.println(myOtherByte2); //0b10000010 -126 + assertEquals( -126, myOtherByte2); + } + + @Test + public void givenString_whenParsingWithWrappers_thenValuesAreReturned(){ + String myString = "127"; + + byte myNewByte = Byte.parseByte(myString); + assertEquals( ((byte)127), myNewByte); + + short myNewShort = Short.parseShort(myString); + assertEquals( ((short)127), myNewShort); + + int myNewInt = Integer.parseInt(myString); + assertEquals( 127, myNewInt); + + long myNewLong = Long.parseLong(myString); + assertEquals( 127L, myNewLong); + + float myNewFloat = Float.parseFloat(myString); + assertEquals( 127.0f, myNewFloat, 0.00001f); + + double myNewDouble = Double.parseDouble(myString); + assertEquals( 127.0, myNewDouble, 0.00001f); + + boolean myNewBoolean = Boolean.parseBoolean(myString); + assertEquals( false, myNewBoolean); //numbers are not true! + + char myNewChar = myString.charAt(0); + assertEquals( 49, myNewChar); //the value of '1' + } + +} From f0c4486cb126f6cbd4e2d51e8aa00e1878bba79d Mon Sep 17 00:00:00 2001 From: maibin Date: Sun, 5 Mar 2017 19:21:35 +0100 Subject: [PATCH 042/291] Ant Colony Optimization updates (#1306) * Ant Colony Optimization * Updated code for Ant Colony --- .../ga/ant_colony/AntColonyOptimization.java | 97 +++++++++---------- .../algorithms/AntColonyOptimizationTest.java | 2 +- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java index e46ac77e84..27a270f906 100644 --- a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java +++ b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java @@ -1,7 +1,10 @@ package com.baeldung.algorithms.ga.ant_colony; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Random; +import java.util.stream.IntStream; public class AntColonyOptimization { @@ -19,7 +22,7 @@ public class AntColonyOptimization { public int numberOfAnts; private double graph[][]; private double trails[][]; - private Ant ants[]; + private List ants = new ArrayList<>(); private Random random = new Random(); private double probabilities[]; @@ -35,101 +38,92 @@ public class AntColonyOptimization { trails = new double[numberOfCities][numberOfCities]; probabilities = new double[numberOfCities]; - ants = new Ant[numberOfAnts]; - for (int j = 0; j < numberOfAnts; j++) { - ants[j] = new Ant(numberOfCities); - } + IntStream.range(0, numberOfAnts).forEach(i -> ants.add(new Ant(numberOfCities))); } /** * Generate initial solution + * * @param n * @return */ public double[][] generateRandomMatrix(int n) { double[][] randomMatrix = new double[n][n]; random.setSeed(System.currentTimeMillis()); - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { + IntStream.range(0, n).forEach(i -> { + IntStream.range(0, n).forEach(j -> { Integer r = random.nextInt(100) + 1; randomMatrix[i][j] = Math.abs(r); - } - } + }); + }); return randomMatrix; } - + /** * Perform ant optimization + * * @return */ - public int[] startAntOptimization() { - int[] finalResult = null; - for (int i = 1; i <= 3; i++) { + public void startAntOptimization() { + IntStream.rangeClosed(1, 3).forEach(i -> { System.out.println("Attempt #" + i); - finalResult = solve(); - } - return finalResult; + solve(); + }); } - + /** * Use this method to run the main logic + * * @return */ - private int[] solve() { + public int[] solve() { setupAnts(); clearTrails(); - int iteration = 0; - while (iteration < maxIterations) { + IntStream.range(0, maxIterations).forEach(i -> { moveAnts(); updateTrails(); updateBest(); - iteration++; - } + }); System.out.println("Best tour length: " + (bestTourLength - numberOfCities)); System.out.println("Best tour order: " + Arrays.toString(bestTourOrder)); return bestTourOrder.clone(); } - + /** * Prepare ants for the simulation */ private void setupAnts() { - currentIndex = -1; - for (int i = 0; i < numberOfAnts; i++) { - ants[i].clear(); - ants[i].visitCity(currentIndex, random.nextInt(numberOfCities)); - } - currentIndex++; + IntStream.range(0, numberOfAnts).forEach(i -> { + ants.stream().forEach(ant -> { + ant.clear(); + ant.visitCity(-1, random.nextInt(numberOfCities)); + }); + }); + currentIndex = 0; } - + /** * At each iteration, move ants */ private void moveAnts() { - while (currentIndex < numberOfCities - 1) { - for (Ant a : ants) - a.visitCity(currentIndex, selectNextCity(a)); + IntStream.range(currentIndex, numberOfCities - 1).forEach(i -> { + ants.stream().forEach(ant -> { + ant.visitCity(currentIndex, selectNextCity(ant)); + }); currentIndex++; - } + }); } - + /** * Select next city for each ant + * * @param ant * @return */ private int selectNextCity(Ant ant) { + int t = random.nextInt(numberOfCities - currentIndex); if (random.nextDouble() < randomFactor) { - int t = random.nextInt(numberOfCities - currentIndex); - int j = -1; - for (int i = 0; i < numberOfCities; i++) { - if (!ant.visited(i)) { - j++; - } - if (j == t) { - return i; - } - } + IntStream.range(0, numberOfCities).filter(i -> i == t && !ant.visited(i)).findFirst(); } calculateProbabilities(ant); double r = random.nextDouble(); @@ -146,9 +140,10 @@ public class AntColonyOptimization { /** * Calculate the next city picks probabilites + * * @param ant */ - private void calculateProbabilities(Ant ant) { + public void calculateProbabilities(Ant ant) { int i = ant.trail[currentIndex]; double pheromone = 0.0; for (int l = 0; l < numberOfCities; l++) { @@ -189,8 +184,8 @@ public class AntColonyOptimization { */ private void updateBest() { if (bestTourOrder == null) { - bestTourOrder = ants[0].trail; - bestTourLength = ants[0].trailLength(graph); + bestTourOrder = ants.get(0).trail; + bestTourLength = ants.get(0).trailLength(graph); } for (Ant a : ants) { if (a.trailLength(graph) < bestTourLength) { @@ -204,9 +199,9 @@ public class AntColonyOptimization { * Clear trails after simulation */ private void clearTrails() { - for (int i = 0; i < numberOfCities; i++) - for (int j = 0; j < numberOfCities; j++) - trails[i][j] = c; + IntStream.range(0, numberOfCities).forEach(i -> { + IntStream.range(0, numberOfCities).forEach(j -> trails[i][j] = c); + }); } } diff --git a/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java b/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java index cd8efaa106..40d2464ab6 100644 --- a/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java +++ b/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java @@ -16,7 +16,7 @@ public class AntColonyOptimizationTest { @Test public void testStartAntOptimization() { AntColonyOptimization antTSP = new AntColonyOptimization(5); - Assert.assertNotNull(antTSP.startAntOptimization()); + Assert.assertNotNull(antTSP.solve()); } } From 6cc10132e18b2e2595409676f0de3053019ee943 Mon Sep 17 00:00:00 2001 From: lor6 Date: Sun, 5 Mar 2017 22:01:51 +0200 Subject: [PATCH 043/291] move rest-angular app to existing rest project (#1293) * move rest-angular app to existing rest project * upgrade boot version --- spring-data-rest/pom.xml | 2 +- .../java/com/baeldung/config/MvcConfig.java | 25 ++++ .../baeldung/repositories/UserRepository.java | 3 +- spring-data-rest/src/main/webapp/users.html | 51 ++++++++ spring-data-rest/src/main/webapp/view/app.js | 122 ++++++++++++++++++ .../SpringDataRelationshipsTest.java | 7 +- 6 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java create mode 100644 spring-data-rest/src/main/webapp/users.html create mode 100644 spring-data-rest/src/main/webapp/view/app.js diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index 4e8001ae7b..1845d60e94 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 1.4.4.RELEASE + 1.5.1.RELEASE diff --git a/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java b/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java new file mode 100644 index 0000000000..bed1a6f846 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/config/MvcConfig.java @@ -0,0 +1,25 @@ +package com.baeldung.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +@EnableWebMvc +public class MvcConfig extends WebMvcConfigurerAdapter{ + + public MvcConfig(){ + super(); + } + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + +} diff --git a/spring-data-rest/src/main/java/com/baeldung/repositories/UserRepository.java b/spring-data-rest/src/main/java/com/baeldung/repositories/UserRepository.java index 0b55ac89b6..2bd9c025dd 100644 --- a/spring-data-rest/src/main/java/com/baeldung/repositories/UserRepository.java +++ b/spring-data-rest/src/main/java/com/baeldung/repositories/UserRepository.java @@ -2,9 +2,10 @@ package com.baeldung.repositories; import org.springframework.data.repository.CrudRepository; import org.springframework.data.rest.core.annotation.RepositoryRestResource; - +import org.springframework.web.bind.annotation.CrossOrigin; import com.baeldung.models.WebsiteUser; +@CrossOrigin @RepositoryRestResource(collectionResourceRel = "users", path = "users") public interface UserRepository extends CrudRepository { diff --git a/spring-data-rest/src/main/webapp/users.html b/spring-data-rest/src/main/webapp/users.html new file mode 100644 index 0000000000..c153f4a36e --- /dev/null +++ b/spring-data-rest/src/main/webapp/users.html @@ -0,0 +1,51 @@ + + + + +User CRUD + + + + + +
+ + + + + + + + + + + + + +
ID:
Name:
Email:
+

+ Get User + Update User + Add User + Delete User + +

+

{{message}}

+

{{errorMessage}}

+ +
+
+ Get all Users
+

+
+ {{usr.name}} {{usr.email}} +
+
+ + \ No newline at end of file diff --git a/spring-data-rest/src/main/webapp/view/app.js b/spring-data-rest/src/main/webapp/view/app.js new file mode 100644 index 0000000000..0bdc6e1979 --- /dev/null +++ b/spring-data-rest/src/main/webapp/view/app.js @@ -0,0 +1,122 @@ +var app = angular.module('app',[]); + +app.controller('UserCRUDCtrl', ['$scope','UserCRUDService', function ($scope,UserCRUDService) { + + $scope.updateUser = function () { + UserCRUDService.updateUser($scope.user.id,$scope.user.name,$scope.user.email) + .then(function success(response){ + $scope.message = 'User data updated!'; + $scope.errorMessage = ''; + }, + function error(response){ + $scope.errorMessage = 'Error updating user!'; + $scope.message = ''; + }); + } + + $scope.getUser = function () { + var id = $scope.user.id; + UserCRUDService.getUser($scope.user.id) + .then(function success(response){ + $scope.user = response.data; + $scope.user.id = id; + $scope.message=''; + $scope.errorMessage = ''; + }, + function error (response ){ + $scope.message = ''; + if (response.status === 404){ + $scope.errorMessage = 'User not found!'; + } + else { + $scope.errorMessage = "Error getting user!"; + } + }); + } + + $scope.addUser = function () { + if ($scope.user != null && $scope.user.name) { + UserCRUDService.addUser($scope.user.name, $scope.user.email) + .then (function success(response){ + $scope.message = 'User added!'; + $scope.errorMessage = ''; + }, + function error(response){ + $scope.errorMessage = 'Error adding user!'; + $scope.message = ''; + }); + } + else { + $scope.errorMessage = 'Please enter a name!'; + $scope.message = ''; + } + } + + $scope.deleteUser = function () { + UserCRUDService.deleteUser($scope.user.id) + .then (function success(response){ + $scope.message = 'User deleted!'; + $scope.user = null; + $scope.errorMessage=''; + }, + function error(response){ + $scope.errorMessage = 'Error deleting user!'; + $scope.message=''; + }) + } + + $scope.getAllUsers = function () { + UserCRUDService.getAllUsers() + .then(function success(response){ + $scope.users = response.data._embedded.users; + $scope.message=''; + $scope.errorMessage = ''; + }, + function error (response ){ + $scope.message=''; + $scope.errorMessage = 'Error getting users!'; + }); + } + +}]); + +app.service('UserCRUDService',['$http', function ($http) { + + this.getUser = function getUser(userId){ + return $http({ + method: 'GET', + url: 'users/'+userId + }); + } + + this.addUser = function addUser(name, email){ + return $http({ + method: 'POST', + url: 'users', + data: {name:name, email:email} + }); + } + + this.deleteUser = function deleteUser(id){ + return $http({ + method: 'DELETE', + url: 'users/'+id + }) + } + + this.updateUser = function updateUser(id,name,email){ + return $http({ + method: 'PATCH', + url: 'users/'+id, + data: {name:name, email:email} + }) + } + + this.getAllUsers = function getAllUsers(){ + return $http({ + method: 'GET', + url: 'users' + }); + } + +}]); \ No newline at end of file diff --git a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java index 21a067a645..43b5dd7da6 100644 --- a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java @@ -18,6 +18,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; +import org.json.JSONException; import static org.junit.Assert.assertEquals; @@ -37,7 +38,7 @@ public class SpringDataRelationshipsTest { private static final String AUTHOR_NAME = "George Orwell"; @Test - public void whenSaveOneToOneRelationship_thenCorrect() { + public void whenSaveOneToOneRelationship_thenCorrect() throws JSONException { Library library = new Library(LIBRARY_NAME); template.postForEntity(LIBRARY_ENDPOINT, library, Library.class); @@ -55,7 +56,7 @@ public class SpringDataRelationshipsTest { } @Test - public void whenSaveOneToManyRelationship_thenCorrect() { + public void whenSaveOneToManyRelationship_thenCorrect() throws JSONException{ Library library = new Library(LIBRARY_NAME); template.postForEntity(LIBRARY_ENDPOINT, library, Library.class); @@ -77,7 +78,7 @@ public class SpringDataRelationshipsTest { } @Test - public void whenSaveManyToManyRelationship_thenCorrect() { + public void whenSaveManyToManyRelationship_thenCorrect() throws JSONException{ Author author1 = new Author(AUTHOR_NAME); template.postForEntity(AUTHOR_ENDPOINT, author1, Author.class); From 5392bdd8f33797cb43876e3ea521752ebe40a346 Mon Sep 17 00:00:00 2001 From: lor6 Date: Sun, 5 Mar 2017 22:05:58 +0200 Subject: [PATCH 044/291] remove extra code (#1294) --- spring-rest-angular/pom.xml | 9 -- .../web/controller/EmployeeController.java | 14 -- .../web/dao/EmployeeCRUDRepository.java | 13 -- .../org/baeldung/web/entity/Employee.java | 57 ------- .../java/org/baeldung/web/main/MvcConfig.java | 36 ----- .../baeldung/web/main/PersistenceConfig.java | 2 +- .../src/main/resources/db/sql/employees.sql | 16 -- .../main/webapp/WEB-INF/pages/employee.html | 55 ------- .../src/main/webapp/view/app.js | 146 +----------------- ...EmployeeCRUDRepositoryIntegrationTest.java | 47 ------ 10 files changed, 3 insertions(+), 392 deletions(-) delete mode 100644 spring-rest-angular/src/main/java/org/baeldung/web/controller/EmployeeController.java delete mode 100644 spring-rest-angular/src/main/java/org/baeldung/web/dao/EmployeeCRUDRepository.java delete mode 100644 spring-rest-angular/src/main/java/org/baeldung/web/entity/Employee.java delete mode 100644 spring-rest-angular/src/main/java/org/baeldung/web/main/MvcConfig.java delete mode 100644 spring-rest-angular/src/main/resources/db/sql/employees.sql delete mode 100644 spring-rest-angular/src/main/webapp/WEB-INF/pages/employee.html delete mode 100644 spring-rest-angular/src/test/java/org/baeldung/web/service/EmployeeCRUDRepositoryIntegrationTest.java diff --git a/spring-rest-angular/pom.xml b/spring-rest-angular/pom.xml index 62ab03522d..b6bc95df81 100644 --- a/spring-rest-angular/pom.xml +++ b/spring-rest-angular/pom.xml @@ -74,15 +74,6 @@ spring-boot-starter-test test - - org.springframework.boot - spring-boot-starter-data-rest - - - javax.servlet - jstl - 1.2 - diff --git a/spring-rest-angular/src/main/java/org/baeldung/web/controller/EmployeeController.java b/spring-rest-angular/src/main/java/org/baeldung/web/controller/EmployeeController.java deleted file mode 100644 index a8bfc254c3..0000000000 --- a/spring-rest-angular/src/main/java/org/baeldung/web/controller/EmployeeController.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.baeldung.web.controller; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -@Controller -public class EmployeeController { - - @RequestMapping(value = "/employeePage") - public String getEmployeePage() { - return "employee"; - } - -} diff --git a/spring-rest-angular/src/main/java/org/baeldung/web/dao/EmployeeCRUDRepository.java b/spring-rest-angular/src/main/java/org/baeldung/web/dao/EmployeeCRUDRepository.java deleted file mode 100644 index 1e5f81ed45..0000000000 --- a/spring-rest-angular/src/main/java/org/baeldung/web/dao/EmployeeCRUDRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.baeldung.web.dao; - -import java.util.List; - -import org.baeldung.web.entity.Employee; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.data.rest.core.annotation.RepositoryRestResource; - -@RepositoryRestResource(collectionResourceRel = "employee", path = "employees") -public interface EmployeeCRUDRepository extends CrudRepository { - List findByName(@Param("name") String name); -} diff --git a/spring-rest-angular/src/main/java/org/baeldung/web/entity/Employee.java b/spring-rest-angular/src/main/java/org/baeldung/web/entity/Employee.java deleted file mode 100644 index 8d6831726c..0000000000 --- a/spring-rest-angular/src/main/java/org/baeldung/web/entity/Employee.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.baeldung.web.entity; - -import java.io.Serializable; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; - -@Entity -public class Employee implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - private long id; - - @Column(nullable = false) - private String name; - - @Column(nullable = false) - private Integer age; - - public Employee() { - } - - public Employee(long id, String name, Integer age) { - super(); - this.id = id; - this.name = name; - this.age = age; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - -} diff --git a/spring-rest-angular/src/main/java/org/baeldung/web/main/MvcConfig.java b/spring-rest-angular/src/main/java/org/baeldung/web/main/MvcConfig.java deleted file mode 100644 index b24aad1177..0000000000 --- a/spring-rest-angular/src/main/java/org/baeldung/web/main/MvcConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.baeldung.web.main; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import org.springframework.web.servlet.view.InternalResourceViewResolver; - -@Configuration -@EnableWebMvc -@ComponentScan("org.baeldung.web.controller") -public class MvcConfig extends WebMvcConfigurerAdapter{ - - public MvcConfig(){ - super(); - } - - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); - } - - @Bean - public ViewResolver viewResolver() { - final InternalResourceViewResolver bean = new InternalResourceViewResolver(); - - bean.setPrefix("/WEB-INF/pages/"); - bean.setSuffix(".html"); - - return bean; - } - -} diff --git a/spring-rest-angular/src/main/java/org/baeldung/web/main/PersistenceConfig.java b/spring-rest-angular/src/main/java/org/baeldung/web/main/PersistenceConfig.java index 8454ce155a..e0f6002733 100644 --- a/spring-rest-angular/src/main/java/org/baeldung/web/main/PersistenceConfig.java +++ b/spring-rest-angular/src/main/java/org/baeldung/web/main/PersistenceConfig.java @@ -26,7 +26,7 @@ public class PersistenceConfig { @Bean public DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); - EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.HSQL).addScript("db/sql/data.sql").addScript("db/sql/employees.sql").build(); + EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.HSQL).addScript("db/sql/data.sql").build(); return db; } diff --git a/spring-rest-angular/src/main/resources/db/sql/employees.sql b/spring-rest-angular/src/main/resources/db/sql/employees.sql deleted file mode 100644 index 366c0c309a..0000000000 --- a/spring-rest-angular/src/main/resources/db/sql/employees.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE employee ( - id INTEGER PRIMARY KEY, - name VARCHAR(30), - age INTEGER -); - -INSERT INTO employee (id,name,age) -VALUES (1,'Bryan',20); -INSERT INTO employee (id,name,age) -VALUES (2,'Lisa',30); -INSERT INTO employee (id,name,age) -VALUES (3,'Laura',40); -INSERT INTO employee (id,name,age) -VALUES (4,'Alex',35); -INSERT INTO employee (id,name,age) -VALUES (5,'John',47); diff --git a/spring-rest-angular/src/main/webapp/WEB-INF/pages/employee.html b/spring-rest-angular/src/main/webapp/WEB-INF/pages/employee.html deleted file mode 100644 index 510e981f25..0000000000 --- a/spring-rest-angular/src/main/webapp/WEB-INF/pages/employee.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - -Employee CRUD - - - - - - -
- - - - - - - - - - - - - -
ID:
Name:
Age:
-

- Get employee - Update employee - Add employee - Delete employee - -

-

{{message}}

-

{{errorMessage}}

- -
-
- Get all Employees

- Name: - Get employees by name -

-
- {{emp.name}} {{emp.age}} -
-
- - \ No newline at end of file diff --git a/spring-rest-angular/src/main/webapp/view/app.js b/spring-rest-angular/src/main/webapp/view/app.js index 9f78d5adf7..b56497807c 100644 --- a/spring-rest-angular/src/main/webapp/view/app.js +++ b/spring-rest-angular/src/main/webapp/view/app.js @@ -5,8 +5,8 @@ app.controller('StudentCtrl', ['$scope','StudentService', function ($scope,Stude pageNumber: 1, pageSize: 5, sort: null - }; - + }; + StudentService.getStudents(paginationOptions.pageNumber, paginationOptions.pageSize).success(function(data){ $scope.gridOptions.data = data.content; @@ -54,145 +54,3 @@ app.service('StudentService',['$http', function ($http) { }; }]); - -app.controller('EmployeeCRUDCtrl', ['$scope','EmployeeCRUDService', function ($scope,EmployeeCRUDService) { - - $scope.updateEmployee = function () { - EmployeeCRUDService.updateEmployee($scope.employee.id,$scope.employee.name,$scope.employee.age) - .then(function success(response){ - $scope.message = 'Employee data updated!'; - $scope.errorMessage = ''; - }, - function error(response){ - $scope.errorMessage = 'Error updating Employee!'; - $scope.message = ''; - }); - } - - $scope.getEmployee = function () { - var id = $scope.employee.id; - EmployeeCRUDService.getEmployee($scope.employee.id) - .then(function success(response){ - $scope.employee = response.data; - $scope.employee.id = id; - $scope.message=''; - $scope.errorMessage = ''; - }, - function error (response ){ - $scope.message = ''; - if (response.status === 404){ - $scope.errorMessage = 'Employee not found!'; - } - else { - $scope.errorMessage = "Error getting Employee!"; - } - }); - } - - $scope.addEmployee = function () { - if ($scope.employee != null && $scope.employee.id) { - EmployeeCRUDService.addEmployee($scope.employee.id, $scope.employee.name, $scope.employee.age) - .then (function success(response){ - $scope.message = 'Employee added!'; - $scope.errorMessage = ''; - }, - function error(response){ - $scope.errorMessage = 'Error adding Employee!'; - $scope.message = ''; - }); - } - else { - $scope.errorMessage = 'Please enter an id!'; - $scope.message = ''; - } - } - - $scope.deleteEmployee = function () { - EmployeeCRUDService.deleteEmployee($scope.employee.id) - .then (function success(response){ - $scope.message = 'Employee deleted!'; - $scope.employee = null; - $scope.errorMessage=''; - }, - function error(response){ - $scope.errorMessage = 'Error deleting Employee!'; - $scope.message=''; - }) - } - - $scope.getAllEmployees = function () { - EmployeeCRUDService.getAllEmployees() - .then(function success(response){ - $scope.employees = response.data._embedded.employee; - $scope.message=''; - $scope.errorMessage = ''; - }, - function error (response ){ - $scope.message=''; - $scope.errorMessage = 'Error getting Employees!'; - }); - } - - $scope.getEmployeesByName = function () { - EmployeeCRUDService.getEmployeesByName($scope.name) - .then(function success(response){ - $scope.employees = response.data._embedded.employee; - $scope.message=''; - $scope.errorMessage = ''; - }, - function error (response ){ - $scope.message=''; - $scope.errorMessage = 'Error getting Employees!'; - }); - } - -}]); - -app.service('EmployeeCRUDService',['$http', function ($http) { - - this.getEmployee = function getEmployee(employeeId){ - return $http({ - method: 'GET', - url:'employees/'+employeeId - }); - } - - this.addEmployee = function addEmployee(id, name, age, gender){ - return $http({ - method: 'POST', - url:'employees', - data: {id:id, name:name, age:age} - }); - } - - this.deleteEmployee = function deleteEmployee(id){ - return $http({ - method: 'DELETE', - url: 'employees/'+id - }) - } - - this.updateEmployee = function updateEmployee(id,name,age){ - return $http({ - method: 'PATCH', - url: 'employees/'+id, - data: {name:name, age:age} - }) - } - - this.getAllEmployees = function getAllEmployees(){ - return $http({ - method: 'GET', - url:'employees' - }); - } - - this.getEmployeesByName = function getEmployeesByName(name){ - return $http({ - method: 'GET', - url:'employees/search/findByName', - params:{name:name} - }); - } - -}]); \ No newline at end of file diff --git a/spring-rest-angular/src/test/java/org/baeldung/web/service/EmployeeCRUDRepositoryIntegrationTest.java b/spring-rest-angular/src/test/java/org/baeldung/web/service/EmployeeCRUDRepositoryIntegrationTest.java deleted file mode 100644 index 57fe793596..0000000000 --- a/spring-rest-angular/src/test/java/org/baeldung/web/service/EmployeeCRUDRepositoryIntegrationTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.baeldung.web.service; - -import static org.junit.Assert.*; - -import org.baeldung.web.entity.Employee; -import org.baeldung.web.main.Application; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT) -public class EmployeeCRUDRepositoryIntegrationTest { - - @Autowired - private TestRestTemplate template; - - private static final String EMPLOYEE_ENDPOINT = "http://localhost:8080/employees/"; - private static int EMPLOYEE_ID = 1; - private static int EMPLOYEE_AGE = 25; - - @Test - public void whenEmployeeCRUDOperations_thenCorrect() { - Employee Employee = new Employee(EMPLOYEE_ID, "Bryan", 20); - ResponseEntity postResponse = template.postForEntity(EMPLOYEE_ENDPOINT, Employee, Employee.class, ""); - assertEquals("status is not 201", HttpStatus.CREATED, postResponse.getStatusCode()); - - Employee.setAge(EMPLOYEE_AGE); - Employee patchResponse = template.patchForObject(EMPLOYEE_ENDPOINT + "/" + EMPLOYEE_ID, Employee, Employee.class); - assertEquals("age is not 25", Integer.valueOf(EMPLOYEE_AGE), patchResponse.getAge()); - - ResponseEntity getResponse = template.getForEntity(EMPLOYEE_ENDPOINT + "/" + EMPLOYEE_ID, Employee.class, ""); - assertEquals("status is not 200", HttpStatus.OK, getResponse.getStatusCode()); - - template.delete(EMPLOYEE_ENDPOINT + "/" + EMPLOYEE_ID); - - getResponse = template.getForEntity(EMPLOYEE_ENDPOINT + "/" + EMPLOYEE_ID, Employee.class, ""); - assertEquals("status is not 404", HttpStatus.NOT_FOUND, getResponse.getStatusCode()); - - } -} From 57259c4a06a45dfdcab31258dfe79774e8a2a918 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Mon, 6 Mar 2017 02:33:15 +0530 Subject: [PATCH 045/291] Twitter4J (#1300) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * Twitter4J * Update Application.java * Update ApplicationTest.java * Update twitter4j.properties --- Twitter4J/pom.xml | 58 +++++++++ .../main/java/com/baeldung/Application.java | 117 ++++++++++++++++++ .../src/main/resources/twitter4j.properties | 4 + .../java/com/baeldung/ApplicationTest.java | 40 ++++++ core-java/0.004102810554955205 | 0 core-java/0.04832801936270381 | 0 core-java/0.5633433244738808 | 0 core-java/0.6256429734439612 | 0 core-java/0.9799201796740292 | 0 9 files changed, 219 insertions(+) create mode 100644 Twitter4J/pom.xml create mode 100644 Twitter4J/src/main/java/com/baeldung/Application.java create mode 100644 Twitter4J/src/main/resources/twitter4j.properties create mode 100644 Twitter4J/src/test/java/com/baeldung/ApplicationTest.java create mode 100644 core-java/0.004102810554955205 create mode 100644 core-java/0.04832801936270381 create mode 100644 core-java/0.5633433244738808 create mode 100644 core-java/0.6256429734439612 create mode 100644 core-java/0.9799201796740292 diff --git a/Twitter4J/pom.xml b/Twitter4J/pom.xml new file mode 100644 index 0000000000..ebe5a7d409 --- /dev/null +++ b/Twitter4J/pom.xml @@ -0,0 +1,58 @@ + + 4.0.0 + com.mabsisa + Twitter4J + jar + 1.0-SNAPSHOT + Twitter4J + http://maven.apache.org + + + UTF-8 + UTF-8 + 1.8 + 1.8 + 1.8 + + + + + org.twitter4j + twitter4j-core + 4.0.6 + + + org.twitter4j + twitter4j-stream + 4.0.6 + + + junit + junit + 4.12 + + + + + ${project.artifactId} + + + src/main/resources + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + **/ApplicationTest.java + + + + + + + diff --git a/Twitter4J/src/main/java/com/baeldung/Application.java b/Twitter4J/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..f7da27db29 --- /dev/null +++ b/Twitter4J/src/main/java/com/baeldung/Application.java @@ -0,0 +1,117 @@ +/** + * + */ +package com.baeldung; + +import java.util.List; +import java.util.stream.Collectors; + +import twitter4j.DirectMessage; +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.StallWarning; +import twitter4j.Status; +import twitter4j.StatusDeletionNotice; +import twitter4j.StatusListener; +import twitter4j.Twitter; +import twitter4j.TwitterException; +import twitter4j.TwitterFactory; +import twitter4j.TwitterStream; +import twitter4j.TwitterStreamFactory; +import twitter4j.conf.ConfigurationBuilder; + +public class Application { + + public static Twitter getTwitterinstance() { + /** + * if not using properties file, we can set access token by following way + */ +// ConfigurationBuilder cb = new ConfigurationBuilder(); +// cb.setDebugEnabled(true) +// .setOAuthConsumerKey("DPHTBsWWO42d8rzshxlK0OwSY") +// .setOAuthConsumerSecret("ACLXkeRY98NiaVCG1ai8fdYt0GoEGJbFeTuxjulSCO7sLKqls1") +// .setOAuthAccessToken("838080188214759428-9MSK1ddPTN5ZZHbddjFI7s75mYgmCFQ") +// .setOAuthAccessTokenSecret("1eXAADpHShAzQh5hGWLBUQHLysOuAKIOapmQQ8U0OVk2c"); +// +// TwitterFactory tf = new TwitterFactory(cb.build()); +// Twitter twitter = tf.getSingleton(); + + Twitter twitter = TwitterFactory.getSingleton(); + return twitter; + + } + + public static String createTweet(String tweet) throws TwitterException { + Twitter twitter = getTwitterinstance(); + Status status = twitter.updateStatus("creating baeldung API"); + return status.getText(); + } + + public static List getTimeLine() throws TwitterException { + Twitter twitter = getTwitterinstance(); + List statuses = twitter.getHomeTimeline(); + return statuses.stream().map( + item -> item.getText()).collect( + Collectors.toList()); + } + + public static String sendDirectMessage(String recipientName, String msg) throws TwitterException { + Twitter twitter = getTwitterinstance(); + DirectMessage message = twitter.sendDirectMessage(recipientName, msg); + return message.getText(); + } + + public static List searchtweets() throws TwitterException { + Twitter twitter = getTwitterinstance(); + Query query = new Query("source:twitter4j baeldung"); + QueryResult result = twitter.search(query); + List statuses = result.getTweets(); + return statuses.stream().map( + item -> item.getText()).collect( + Collectors.toList()); + } + + public static void streamFeed() { + + StatusListener listener = new StatusListener(){ + + @Override + public void onException(Exception e) { + e.printStackTrace(); + } + + @Override + public void onDeletionNotice(StatusDeletionNotice arg) { + System.out.println("Got a status deletion notice id:" + arg.getStatusId()); + } + + @Override + public void onScrubGeo(long userId, long upToStatusId) { + System.out.println("Got scrub_geo event userId:" + userId + " upToStatusId:" + upToStatusId); + } + + @Override + public void onStallWarning(StallWarning warning) { + System.out.println("Got stall warning:" + warning); + } + + @Override + public void onStatus(Status status) { + System.out.println(status.getUser().getName() + " : " + status.getText()); + } + + @Override + public void onTrackLimitationNotice(int numberOfLimitedStatuses) { + System.out.println("Got track limitation notice:" + numberOfLimitedStatuses); + } + }; + + TwitterStream twitterStream = new TwitterStreamFactory().getInstance(); + + twitterStream.addListener(listener); + + twitterStream.sample(); + + } + +} diff --git a/Twitter4J/src/main/resources/twitter4j.properties b/Twitter4J/src/main/resources/twitter4j.properties new file mode 100644 index 0000000000..ee11dc62a1 --- /dev/null +++ b/Twitter4J/src/main/resources/twitter4j.properties @@ -0,0 +1,4 @@ +oauth.consumerKey=//TODO +oauth.consumerSecret=//TODO +oauth.accessToken=//TODO +oauth.accessTokenSecret=//TODO diff --git a/Twitter4J/src/test/java/com/baeldung/ApplicationTest.java b/Twitter4J/src/test/java/com/baeldung/ApplicationTest.java new file mode 100644 index 0000000000..a1c778679c --- /dev/null +++ b/Twitter4J/src/test/java/com/baeldung/ApplicationTest.java @@ -0,0 +1,40 @@ +package com.baeldung; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import twitter4j.TwitterException; + +public class ApplicationTest { + + /** + * In order run this jUnit test you need to configure your API details in the twitter4j.properties + */ + + String tweet = "baeldung is awsome"; + + @Test + public void givenText_updateStatus() throws TwitterException { + String text = Application.createTweet(tweet); + assertEquals(tweet, text); + } + + @Test + public void givenCredential_fetchStatus() throws TwitterException { + List statuses = Application.getTimeLine(); + List expectedStatuses = new ArrayList(); + expectedStatuses.add(tweet); + assertEquals(expectedStatuses, statuses); + } + + @Test + public void givenRecipientNameAndMessage_sendDirectMessage() throws TwitterException { + String msg = Application.sendDirectMessage("YOUR_RECCIPIENT_ID", tweet); + assertEquals(msg, tweet); + } + +} diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292 new file mode 100644 index 0000000000..e69de29bb2 From 90969c9d58a104082d5105174831b0abe845e709 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Sun, 5 Mar 2017 19:20:14 -0600 Subject: [PATCH 046/291] BAEL-9: README.md file updated (#1310) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md --- spring-boot/README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 78ef3c843c..9fe18aaacc 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -10,4 +10,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [The @ServletComponentScan Annotation in Spring Boot](http://www.baeldung.com/spring-servletcomponentscan) - [A Custom Data Binder in Spring MVC](http://www.baeldung.com/spring-mvc-custom-data-binder) - [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) -- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/how-to-register-a-servlet-in-a-java-web-application/) +- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) From 693f7b96892ab5dd44bb1040f20b59d5a1a541ae Mon Sep 17 00:00:00 2001 From: Tryfon Date: Mon, 6 Mar 2017 09:37:08 +0200 Subject: [PATCH 047/291] Guide to "when" block in Kotlin pull request (#1296) * Char array to string and string to char array test cases added * Minor code renames * Added groupingBy collector unit tests * Added test case for int summary calculation on grouped results * Added the grouping by classes to the main source path * Reverting char array to string test class * Reverting char array to string test class * Reverting char array to string test class * Reverting char array to string test class * Unit test class for Kotlin when block + required types * Minor changes to kotlin when block tests * Minor change * Minor change --- .../com/baeldung/kotlin/WhenBlockTypes.kt | 28 ++++ .../com/baeldung/kotlin/WhenBlockUnitTest.kt | 136 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 kotlin/src/main/kotlin/com/baeldung/kotlin/WhenBlockTypes.kt create mode 100644 kotlin/src/test/kotlin/com/baeldung/kotlin/WhenBlockUnitTest.kt diff --git a/kotlin/src/main/kotlin/com/baeldung/kotlin/WhenBlockTypes.kt b/kotlin/src/main/kotlin/com/baeldung/kotlin/WhenBlockTypes.kt new file mode 100644 index 0000000000..6180da10d9 --- /dev/null +++ b/kotlin/src/main/kotlin/com/baeldung/kotlin/WhenBlockTypes.kt @@ -0,0 +1,28 @@ +package com.baeldung.kotlin + +enum class UnixFileType { + D, HYPHEN_MINUS, L +} + +sealed class UnixFile { + + abstract fun getFileType(): UnixFileType + + class RegularFile(val content: String) : UnixFile() { + override fun getFileType(): UnixFileType { + return UnixFileType.HYPHEN_MINUS + } + } + + class Directory(val children: List) : UnixFile() { + override fun getFileType(): UnixFileType { + return UnixFileType.D + } + } + + class SymbolicLink(val originalFile: UnixFile) : UnixFile() { + override fun getFileType(): UnixFileType { + return UnixFileType.L + } + } +} \ No newline at end of file diff --git a/kotlin/src/test/kotlin/com/baeldung/kotlin/WhenBlockUnitTest.kt b/kotlin/src/test/kotlin/com/baeldung/kotlin/WhenBlockUnitTest.kt new file mode 100644 index 0000000000..aa1891fa46 --- /dev/null +++ b/kotlin/src/test/kotlin/com/baeldung/kotlin/WhenBlockUnitTest.kt @@ -0,0 +1,136 @@ +package com.baeldung.kotlin + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class WhenBlockUnitTest { + + @Test + fun testWhenExpression() { + val directoryType = UnixFileType.D + + val objectType = when (directoryType) { + UnixFileType.D -> "d" + UnixFileType.HYPHEN_MINUS -> "-" + UnixFileType.L -> "l" + } + + assertEquals("d", objectType) + } + + @Test + fun testWhenExpressionWithDefaultCase() { + val fileType = UnixFileType.L + + val result = when (fileType) { + UnixFileType.L -> "linking to another file" + else -> "not a link" + } + + assertEquals("linking to another file", result) + } + + @Test(expected = IllegalArgumentException::class) + fun testWhenExpressionWithThrowException() { + val fileType = UnixFileType.L + + val result: Boolean = when (fileType) { + UnixFileType.HYPHEN_MINUS -> true + else -> throw IllegalArgumentException("Wrong type of file") + } + } + + @Test + fun testWhenStatement() { + val fileType = UnixFileType.HYPHEN_MINUS + + when (fileType) { + UnixFileType.HYPHEN_MINUS -> println("Regular file type") + UnixFileType.D -> println("Directory file type") + } + } + + @Test + fun testCaseCombination() { + val fileType = UnixFileType.D + + val frequentFileType: Boolean = when (fileType) { + UnixFileType.HYPHEN_MINUS, UnixFileType.D -> true + else -> false + } + + assertTrue(frequentFileType) + } + + @Test + fun testWhenWithoutArgument() { + val fileType = UnixFileType.L + + val objectType = when { + fileType === UnixFileType.L -> "l" + fileType === UnixFileType.HYPHEN_MINUS -> "-" + fileType === UnixFileType.D -> "d" + else -> "unknown file type" + } + + assertEquals("l", objectType) + } + + @Test + fun testDynamicCaseExpression() { + val unixFile = UnixFile.SymbolicLink(UnixFile.RegularFile("Content")) + + when { + unixFile.getFileType() == UnixFileType.D -> println("It's a directory!") + unixFile.getFileType() == UnixFileType.HYPHEN_MINUS -> println("It's a regular file!") + unixFile.getFileType() == UnixFileType.L -> println("It's a soft link!") + } + } + + @Test + fun testCollectionCaseExpressions() { + val regularFile = UnixFile.RegularFile("Test Content") + val symbolicLink = UnixFile.SymbolicLink(regularFile) + val directory = UnixFile.Directory(listOf(regularFile, symbolicLink)) + + val isRegularFileInDirectory = when (regularFile) { + in directory.children -> true + else -> false + } + + val isSymbolicLinkInDirectory = when { + symbolicLink in directory.children -> true + else -> false + } + + assertTrue(isRegularFileInDirectory) + assertTrue(isSymbolicLinkInDirectory) + } + + @Test + fun testRangeCaseExpressions() { + val fileType = UnixFileType.HYPHEN_MINUS + + val isCorrectType = when (fileType) { + in UnixFileType.D..UnixFileType.L -> true + else -> false + } + + assertTrue(isCorrectType) + } + + @Test + fun testWhenWithIsOperatorWithSmartCase() { + val unixFile: UnixFile = UnixFile.RegularFile("Test Content") + + val result = when (unixFile) { + is UnixFile.RegularFile -> unixFile.content + is UnixFile.Directory -> unixFile.children.map { it.getFileType() }.joinToString(", ") + is UnixFile.SymbolicLink -> unixFile.originalFile.getFileType() + } + + assertEquals("Test Content", result) + } + +} \ No newline at end of file From 1ff8b4c69c26de7e5d496f4c85e4ec5b8749a5e5 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 6 Mar 2017 11:34:27 +0100 Subject: [PATCH 048/291] Bael 655 (#1256) BAEL-655 hbase --- hbase/pom.xml | 51 +++++ .../baeldung/hbase/HBaseClientOperations.java | 193 ++++++++++++++++++ .../baeldung/hbase/HbaseClientExample.java | 38 ++++ hbase/src/main/resources/hbase-site.xml | 12 ++ pom.xml | 1 + 5 files changed, 295 insertions(+) create mode 100644 hbase/pom.xml create mode 100644 hbase/src/main/java/org/baeldung/hbase/HBaseClientOperations.java create mode 100644 hbase/src/main/java/org/baeldung/hbase/HbaseClientExample.java create mode 100644 hbase/src/main/resources/hbase-site.xml diff --git a/hbase/pom.xml b/hbase/pom.xml new file mode 100644 index 0000000000..2382e47af2 --- /dev/null +++ b/hbase/pom.xml @@ -0,0 +1,51 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + hbase + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + + org.apache.hbase + hbase-client + ${hbase.version} + + + org.apache.hbase + hbase + ${hbase.version} + + + junit + junit + ${junit.version} + test + + + + + 1.3.0 + 4.12 + + + + \ No newline at end of file diff --git a/hbase/src/main/java/org/baeldung/hbase/HBaseClientOperations.java b/hbase/src/main/java/org/baeldung/hbase/HBaseClientOperations.java new file mode 100644 index 0000000000..c78eacc834 --- /dev/null +++ b/hbase/src/main/java/org/baeldung/hbase/HBaseClientOperations.java @@ -0,0 +1,193 @@ +package org.baeldung.hbase; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.*; +import org.apache.hadoop.hbase.filter.*; +import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; +import org.apache.hadoop.hbase.filter.FilterList.Operator; +import org.apache.hadoop.hbase.util.Bytes; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class HBaseClientOperations { + private final static byte[] cellData = Bytes.toBytes("cell_data"); + + /** + * Drop tables if this value is set true. + */ + static boolean INITIALIZE_AT_FIRST = true; + + /** + * + * + * Row1Family1:Qualifier1Family1:Qualifier2 + * + * + * Row2Family1:Qualifier1Family2:Qualifier3 + * + * + * Row3Family1:Qualifier1Family2:Qualifier3 + * + *
+ */ + private final TableName table1 = TableName.valueOf("Table1"); + private final String family1 = "Family1"; + private final String family2 = "Family2"; + + private final byte[] row1 = Bytes.toBytes("Row1"); + private final byte[] row2 = Bytes.toBytes("Row2"); + private final byte[] row3 = Bytes.toBytes("Row3"); + private final byte[] qualifier1 = Bytes.toBytes("Qualifier1"); + private final byte[] qualifier2 = Bytes.toBytes("Qualifier2"); + private final byte[] qualifier3 = Bytes.toBytes("Qualifier3"); + + private void createTable(Admin admin) throws IOException { + HTableDescriptor desc = new HTableDescriptor(table1); + desc.addFamily(new HColumnDescriptor(family1)); + desc.addFamily(new HColumnDescriptor(family2)); + admin.createTable(desc); + } + + private void delete(Table table) throws IOException { + final byte[] rowToBeDeleted = Bytes.toBytes("RowToBeDeleted"); + System.out.println("\n*** DELETE ~Insert data and then delete it~ ***"); + + System.out.println("Inserting a data to be deleted later."); + Put put = new Put(rowToBeDeleted); + put.addColumn(family1.getBytes(), qualifier1, cellData); + table.put(put); + + Get get = new Get(rowToBeDeleted); + Result result = table.get(get); + byte[] value = result.getValue(family1.getBytes(), qualifier1); + System.out.println("Fetch the data: " + Bytes.toString(value)); + assert Arrays.equals(cellData, value); + + System.out.println("Deleting"); + Delete delete = new Delete(rowToBeDeleted); + delete.addColumn(family1.getBytes(), qualifier1); + table.delete(delete); + + result = table.get(get); + value = result.getValue(family1.getBytes(), qualifier1); + System.out.println("Fetch the data: " + Bytes.toString(value)); + assert Arrays.equals(null, value); + + System.out.println("Done. "); + } + + private void deleteTable(Admin admin) throws IOException { + if (admin.tableExists(table1)) { + admin.disableTable(table1); + admin.deleteTable(table1); + } + } + + private void filters(Table table) throws IOException { + System.out.println("\n*** FILTERS ~ scanning with filters to fetch a row of which key is larget than \"Row1\"~ ***"); + Filter filter1 = new PrefixFilter(row1); + Filter filter2 = new QualifierFilter(CompareOp.GREATER_OR_EQUAL, new BinaryComparator( + qualifier1)); + + List filters = Arrays.asList(filter1, filter2); + + Scan scan = new Scan(); + scan.setFilter(new FilterList(Operator.MUST_PASS_ALL, filters)); + + try (ResultScanner scanner = table.getScanner(scan)) { + int i = 0; + for (Result result : scanner) { + System.out.println("Filter " + scan.getFilter() + " matched row: " + result); + i++; + } + assert i == 2 : "This filtering sample should return 1 row but was " + i + "."; + } + System.out.println("Done. "); + } + + private void get(Table table) throws IOException { + System.out.println("\n*** GET example ~fetching the data in Family1:Qualifier1~ ***"); + + Get g = new Get(row1); + Result r = table.get(g); + byte[] value = r.getValue(family1.getBytes(), qualifier1); + + System.out.println("Fetched value: " + Bytes.toString(value)); + assert Arrays.equals(cellData, value); + System.out.println("Done. "); + } + + private void put(Admin admin, Table table) throws IOException { + System.out.println("\n*** PUT example ~inserting \"cell-data\" into Family1:Qualifier1 of Table1 ~ ***"); + + // Row1 => Family1:Qualifier1, Family1:Qualifier2 + Put p = new Put(row1); + p.addImmutable(family1.getBytes(), qualifier1, cellData); + p.addImmutable(family1.getBytes(), qualifier2, cellData); + table.put(p); + + // Row2 => Family1:Qualifier1, Family2:Qualifier3 + p = new Put(row2); + p.addImmutable(family1.getBytes(), qualifier1, cellData); + p.addImmutable(family2.getBytes(), qualifier3, cellData); + table.put(p); + + // Row3 => Family1:Qualifier1, Family2:Qualifier3 + p = new Put(row3); + p.addImmutable(family1.getBytes(), qualifier1, cellData); + p.addImmutable(family2.getBytes(), qualifier3, cellData); + table.put(p); + + admin.disableTable(table1); + try { + HColumnDescriptor desc = new HColumnDescriptor(row1); + admin.addColumn(table1, desc); + System.out.println("Success."); + } catch (Exception e) { + System.out.println("Failed."); + System.out.println(e.getMessage()); + } finally { + admin.enableTable(table1); + } + System.out.println("Done. "); + } + + public void run(Configuration config) throws IOException { + try (Connection connection = ConnectionFactory.createConnection(config)) { + + Admin admin = connection.getAdmin(); + if (INITIALIZE_AT_FIRST) { + deleteTable(admin); + } + + if (!admin.tableExists(table1)) { + createTable(admin); + } + + Table table = connection.getTable(table1); + put(admin, table); + get(table); + scan(table); + filters(table); + delete(table); + } + } + + private void scan(Table table) throws IOException { + System.out.println("\n*** SCAN example ~fetching data in Family1:Qualifier1 ~ ***"); + + Scan scan = new Scan(); + scan.addColumn(family1.getBytes(), qualifier1); + + try (ResultScanner scanner = table.getScanner(scan)) { + for (Result result : scanner) + System.out.println("Found row: " + result); + } + System.out.println("Done."); + } +} \ No newline at end of file diff --git a/hbase/src/main/java/org/baeldung/hbase/HbaseClientExample.java b/hbase/src/main/java/org/baeldung/hbase/HbaseClientExample.java new file mode 100644 index 0000000000..07cb7df480 --- /dev/null +++ b/hbase/src/main/java/org/baeldung/hbase/HbaseClientExample.java @@ -0,0 +1,38 @@ +package org.baeldung.hbase; + + +import com.google.protobuf.ServiceException; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.MasterNotRunningException; +import org.apache.hadoop.hbase.client.HBaseAdmin; + +import java.io.IOException; + +//install hbase locally & hbase master start +public class HbaseClientExample { + + public static void main(String[] args) throws IOException, ServiceException { + new HbaseClientExample().connect(); + } + + private void connect() throws IOException, ServiceException { + Configuration config = HBaseConfiguration.create(); + + String path = this.getClass().getClassLoader().getResource("hbase-site.xml").getPath(); + + config.addResource(new Path(path)); + + try { + HBaseAdmin.checkHBaseAvailable(config); + } catch (MasterNotRunningException e) { + System.out.println("HBase is not running." + e.getMessage()); + return; + } + + HBaseClientOperations HBaseClientOperations = new HBaseClientOperations(); + HBaseClientOperations.run(config); + } + +} \ No newline at end of file diff --git a/hbase/src/main/resources/hbase-site.xml b/hbase/src/main/resources/hbase-site.xml new file mode 100644 index 0000000000..895529161c --- /dev/null +++ b/hbase/src/main/resources/hbase-site.xml @@ -0,0 +1,12 @@ + + + + + hbase.zookeeper.quorum + localhost + + + hbase.zookeeper.property.clientPort + 2181 + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 72099fc584..9c24200a0b 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ handling-spring-static-resources hazelcast + httpclient hystrix From 9f94f9f78996a42c314168987138905d49f6e95e Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 6 Mar 2017 14:06:00 +0100 Subject: [PATCH 049/291] Remove unnecessary files and update .gitignore (#1313) --- core-java/.gitignore | 3 + .../.resourceCache/ECBCurrentRateProvider.dat | 42 ------- .../ECBHistoric90RateProvider.dat | 63 ---------- .../IMFHistoricRateProvider.dat | 118 ------------------ core-java/.resourceCache/IMFRateProvider.dat | 118 ------------------ core-java/0.004102810554955205 | 0 core-java/0.04832801936270381 | 0 core-java/0.5633433244738808 | 0 core-java/0.6256429734439612 | 0 core-java/0.9799201796740292 | 0 10 files changed, 3 insertions(+), 341 deletions(-) delete mode 100644 core-java/.resourceCache/ECBCurrentRateProvider.dat delete mode 100644 core-java/.resourceCache/ECBHistoric90RateProvider.dat delete mode 100644 core-java/.resourceCache/IMFHistoricRateProvider.dat delete mode 100644 core-java/.resourceCache/IMFRateProvider.dat delete mode 100644 core-java/0.004102810554955205 delete mode 100644 core-java/0.04832801936270381 delete mode 100644 core-java/0.5633433244738808 delete mode 100644 core-java/0.6256429734439612 delete mode 100644 core-java/0.9799201796740292 diff --git a/core-java/.gitignore b/core-java/.gitignore index 251a8755bd..2a03a0f72e 100644 --- a/core-java/.gitignore +++ b/core-java/.gitignore @@ -1,11 +1,14 @@ *.class +0.* + #folders# /target /neoDb* /data /src/main/webapp/WEB-INF/classes */META-INF/* +.resourceCache # Packaged files # *.jar diff --git a/core-java/.resourceCache/ECBCurrentRateProvider.dat b/core-java/.resourceCache/ECBCurrentRateProvider.dat deleted file mode 100644 index 69eed9a0d8..0000000000 --- a/core-java/.resourceCache/ECBCurrentRateProvider.dat +++ /dev/null @@ -1,42 +0,0 @@ - - - Reference rates - - European Central Bank - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core-java/.resourceCache/ECBHistoric90RateProvider.dat b/core-java/.resourceCache/ECBHistoric90RateProvider.dat deleted file mode 100644 index 157cac1a6a..0000000000 --- a/core-java/.resourceCache/ECBHistoric90RateProvider.dat +++ /dev/null @@ -1,63 +0,0 @@ -Reference ratesEuropean Central Bank - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core-java/.resourceCache/IMFHistoricRateProvider.dat b/core-java/.resourceCache/IMFHistoricRateProvider.dat deleted file mode 100644 index 12809d35af..0000000000 --- a/core-java/.resourceCache/IMFHistoricRateProvider.dat +++ /dev/null @@ -1,118 +0,0 @@ -SDRs per Currency unit and Currency units per SDR (1) -last five days -SDRs per Currency unit (2) - -Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 -Chinese Yuan 0.1078010000 0.1075250000 0.1075530000 0.1074200000 -Euro 0.7811130000 0.7827060000 0.7826360000 0.7829640000 -Japanese Yen 0.0065627100 0.0065625100 0.0065915500 0.0065398200 -U.K. Pound Sterling 0.9132630000 0.9188320000 0.9178430000 0.9263250000 -U.S. Dollar 0.7415860000 0.7386110000 0.7392420000 0.7380190000 -Algerian Dinar 0.0067127200 0.0067093100 0.0067141700 0.0067056800 -Australian Dollar 0.5677580000 0.5678440000 0.5688470000 0.5695290000 -Bahrain Dinar 1.9723000000 1.9643900000 1.9660700000 1.9628200000 -Botswana Pula 0.0711181000 0.0711282000 0.0712629000 0.0712926000 -Brazilian Real 0.2393220000 0.2383620000 0.2385650000 0.2409310000 -Brunei Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 -Canadian Dollar 0.5575260000 0.5642640000 0.5632010000 -Chilean Peso 0.0011428700 0.0011448000 0.0011449400 0.0011525100 -Colombian Peso 0.0002540400 0.0002550210 0.0002561010 0.0002570000 -Czech Koruna 0.0289072000 0.0289685000 0.0289649000 0.0289783000 -Danish Krone 0.1050820000 0.1052990000 0.1052900000 0.1053170000 -Hungarian Forint 0.0025403700 0.0025419400 0.0025407000 0.0025337100 -Icelandic Krona 0.0069632500 0.0069197200 0.0068709200 0.0068082900 -Indian Rupee 0.0110936000 0.0110674000 0.0110790000 -Indonesian Rupiah 0.0000555038 0.0000553391 0.0000554196 0.0000553404 -Iranian Rial 0.0000228835 0.0000227945 0.0000228133 -Israeli New Sheqel 0.2041810000 0.2018610000 0.2009360000 0.1995720000 -Kazakhstani Tenge 0.0023615900 0.0023658000 0.0023693200 -Korean Won 0.0006524260 0.0006536180 0.0006480670 -Kuwaiti Dinar 2.4274500000 2.4193000000 2.4213600000 2.4165700000 -Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1667420000 0.1661670000 0.1663840000 0.1659960000 -Mauritian Rupee 0.0208473000 0.0207651000 0.0207673000 -Mexican Peso 0.0369385000 0.0372748000 0.0372107000 -Nepalese Rupee 0.0069436900 0.0069210200 0.0069133300 0.0069012400 -New Zealand Dollar 0.5305310000 0.5304700000 0.5318850000 0.5331450000 -Norwegian Krone 0.0881434000 0.0882493000 0.0885500000 0.0886062000 -Rial Omani 1.9287000000 1.9209600000 1.9226100000 1.9194300000 -Pakistani Rupee 0.0070732900 0.0070443600 0.0070502500 0.0070384300 -Nuevo Sol 0.2266370000 0.2274590000 0.2271530000 -Philippine Peso 0.0147565000 0.0146938000 0.0147268000 0.0146922000 -Polish Zloty 0.1819580000 0.1811650000 0.1814310000 0.1814160000 -Qatar Riyal 0.2037320000 0.2029150000 0.2030880000 0.2027520000 -Russian Ruble 0.0127033000 0.0127429000 0.0127594000 -Saudi Arabian Riyal 0.1977560000 0.1969630000 0.1971310000 0.1968050000 -Singapore Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 -South African Rand 0.0567982000 0.0567078000 0.0569908000 0.0569347000 -Sri Lanka Rupee 0.0049030500 0.0048833800 0.0048875500 -Swedish Krona 0.0818510000 0.0817029000 0.0818978000 0.0822544000 -Swiss Franc 0.7340980000 0.7348630000 0.7341760000 0.7345670000 -Thai Baht 0.0211936000 0.0211661000 0.0212042000 0.0211098000 -Trinidad And Tobago Dollar 0.1102220000 0.1092030000 -Tunisian Dinar 0.3225800000 0.3211100000 0.3215340000 0.3206630000 -U.A.E. Dirham 0.2019290000 0.2011190000 0.2012910000 0.2009580000 -Peso Uruguayo 0.0258745000 -Bolivar Fuerte 0.0743445000 0.0740462000 0.0741095000 0.0739869000 - -Currency units per SDR(3) - -Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 -Chinese Yuan 9.276350 9.300160 9.297740 9.309250 -Euro 1.280220 1.277620 1.277730 1.277200 -Japanese Yen 152.376000 152.381000 151.709000 152.909000 -U.K. Pound Sterling 1.094970 1.088340 1.089510 1.079530 -U.S. Dollar 1.348460 1.353890 1.352740 1.354980 -Algerian Dinar 148.971000 149.047000 148.939000 149.127000 -Australian Dollar 1.761310 1.761050 1.757940 1.755840 -Bahrain Dinar 0.507022 0.509064 0.508629 0.509471 -Botswana Pula 14.061100 14.059100 14.032500 14.026700 -Brazilian Real 4.178470 4.195300 4.191730 4.150570 -Brunei Dollar 1.897550 1.900870 1.900460 1.903340 -Canadian Dollar 1.793640 1.772220 1.775570 -Chilean Peso 874.990000 873.515000 873.408000 867.671000 -Colombian Peso 3,936.390000 3,921.250000 3,904.710000 3,891.050000 -Czech Koruna 34.593500 34.520300 34.524500 34.508600 -Danish Krone 9.516380 9.496770 9.497580 9.495140 -Hungarian Forint 393.643000 393.400000 393.592000 394.678000 -Icelandic Krona 143.611000 144.515000 145.541000 146.880000 -Indian Rupee 90.142100 90.355500 90.260900 -Indonesian Rupiah 18,016.800000 18,070.400000 18,044.200000 18,070.000000 -Iranian Rial 43,699.600000 43,870.200000 43,834.100000 -Israeli New Sheqel 4.897620 4.953900 4.976710 5.010720 -Kazakhstani Tenge 423.444000 422.690000 422.062000 -Korean Won 1,532.740000 1,529.950000 1,543.050000 -Kuwaiti Dinar 0.411955 0.413343 0.412991 0.413810 -Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 5.997290 6.018040 6.010190 6.024240 -Mauritian Rupee 47.967800 48.157700 48.152600 -Mexican Peso 27.072000 26.827800 26.874000 -Nepalese Rupee 144.016000 144.487000 144.648000 144.901000 -New Zealand Dollar 1.884900 1.885120 1.880110 1.875660 -Norwegian Krone 11.345100 11.331500 11.293100 11.285900 -Rial Omani 0.518484 0.520573 0.520126 0.520988 -Pakistani Rupee 141.377000 141.958000 141.839000 142.077000 -Nuevo Sol 4.412340 4.396400 4.402320 -Philippine Peso 67.766700 68.055900 67.903400 68.063300 -Polish Zloty 5.495770 5.519830 5.511740 5.512190 -Qatar Riyal 4.908410 4.928170 4.923970 4.932130 -Russian Ruble 78.719700 78.475100 78.373600 -Saudi Arabian Riyal 5.056740 5.077100 5.072770 5.081170 -Singapore Dollar 1.897550 1.900870 1.900460 1.903340 -South African Rand 17.606200 17.634300 17.546700 17.564000 -Sri Lanka Rupee 203.955000 204.776000 204.601000 -Swedish Krona 12.217300 12.239500 12.210300 12.157400 -Swiss Franc 1.362220 1.360800 1.362070 1.361350 -Thai Baht 47.184100 47.245400 47.160500 47.371400 -Trinidad And Tobago Dollar 9.072600 9.157260 -Tunisian Dinar 3.100010 3.114200 3.110090 3.118540 -U.A.E. Dirham 4.952240 4.972180 4.967930 4.976160 -Peso Uruguayo 38.648100 -Bolivar Fuerte 13.450900 13.505100 13.493500 13.515900 - - -(1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. - -(2) The value of the U.S. dollar in terms of the SDR is the reciprocal of the sum of the dollar values, based on market exchange rates, of specified quantities of the SDR basket currencies. See SDR Valuation.The value in terms of the SDR of each of the other currencies shown above is derived from that currency's representative exchange rate against the U.S. dollar as reported by the issuing central bank and the SDR value of the U.S. dollar, except for the Iranian rial and the Libyan dinar, the values of which are officially expressed directly in terms of domestic currency units per SDR. All figures are rounded to six significant digits. See Representative Exchange Rates for Selected Currencies". - -(3) The value in terms of each national currency of the SDR is the reciprocal of the value in terms of the SDR of each national currency, rounded to six significant digits. \ No newline at end of file diff --git a/core-java/.resourceCache/IMFRateProvider.dat b/core-java/.resourceCache/IMFRateProvider.dat deleted file mode 100644 index 12809d35af..0000000000 --- a/core-java/.resourceCache/IMFRateProvider.dat +++ /dev/null @@ -1,118 +0,0 @@ -SDRs per Currency unit and Currency units per SDR (1) -last five days -SDRs per Currency unit (2) - -Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 -Chinese Yuan 0.1078010000 0.1075250000 0.1075530000 0.1074200000 -Euro 0.7811130000 0.7827060000 0.7826360000 0.7829640000 -Japanese Yen 0.0065627100 0.0065625100 0.0065915500 0.0065398200 -U.K. Pound Sterling 0.9132630000 0.9188320000 0.9178430000 0.9263250000 -U.S. Dollar 0.7415860000 0.7386110000 0.7392420000 0.7380190000 -Algerian Dinar 0.0067127200 0.0067093100 0.0067141700 0.0067056800 -Australian Dollar 0.5677580000 0.5678440000 0.5688470000 0.5695290000 -Bahrain Dinar 1.9723000000 1.9643900000 1.9660700000 1.9628200000 -Botswana Pula 0.0711181000 0.0711282000 0.0712629000 0.0712926000 -Brazilian Real 0.2393220000 0.2383620000 0.2385650000 0.2409310000 -Brunei Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 -Canadian Dollar 0.5575260000 0.5642640000 0.5632010000 -Chilean Peso 0.0011428700 0.0011448000 0.0011449400 0.0011525100 -Colombian Peso 0.0002540400 0.0002550210 0.0002561010 0.0002570000 -Czech Koruna 0.0289072000 0.0289685000 0.0289649000 0.0289783000 -Danish Krone 0.1050820000 0.1052990000 0.1052900000 0.1053170000 -Hungarian Forint 0.0025403700 0.0025419400 0.0025407000 0.0025337100 -Icelandic Krona 0.0069632500 0.0069197200 0.0068709200 0.0068082900 -Indian Rupee 0.0110936000 0.0110674000 0.0110790000 -Indonesian Rupiah 0.0000555038 0.0000553391 0.0000554196 0.0000553404 -Iranian Rial 0.0000228835 0.0000227945 0.0000228133 -Israeli New Sheqel 0.2041810000 0.2018610000 0.2009360000 0.1995720000 -Kazakhstani Tenge 0.0023615900 0.0023658000 0.0023693200 -Korean Won 0.0006524260 0.0006536180 0.0006480670 -Kuwaiti Dinar 2.4274500000 2.4193000000 2.4213600000 2.4165700000 -Libyan Dinar 0.5174910000 0.5174910000 0.5174910000 0.5174910000 -Malaysian Ringgit 0.1667420000 0.1661670000 0.1663840000 0.1659960000 -Mauritian Rupee 0.0208473000 0.0207651000 0.0207673000 -Mexican Peso 0.0369385000 0.0372748000 0.0372107000 -Nepalese Rupee 0.0069436900 0.0069210200 0.0069133300 0.0069012400 -New Zealand Dollar 0.5305310000 0.5304700000 0.5318850000 0.5331450000 -Norwegian Krone 0.0881434000 0.0882493000 0.0885500000 0.0886062000 -Rial Omani 1.9287000000 1.9209600000 1.9226100000 1.9194300000 -Pakistani Rupee 0.0070732900 0.0070443600 0.0070502500 0.0070384300 -Nuevo Sol 0.2266370000 0.2274590000 0.2271530000 -Philippine Peso 0.0147565000 0.0146938000 0.0147268000 0.0146922000 -Polish Zloty 0.1819580000 0.1811650000 0.1814310000 0.1814160000 -Qatar Riyal 0.2037320000 0.2029150000 0.2030880000 0.2027520000 -Russian Ruble 0.0127033000 0.0127429000 0.0127594000 -Saudi Arabian Riyal 0.1977560000 0.1969630000 0.1971310000 0.1968050000 -Singapore Dollar 0.5269940000 0.5260760000 0.5261880000 0.5253930000 -South African Rand 0.0567982000 0.0567078000 0.0569908000 0.0569347000 -Sri Lanka Rupee 0.0049030500 0.0048833800 0.0048875500 -Swedish Krona 0.0818510000 0.0817029000 0.0818978000 0.0822544000 -Swiss Franc 0.7340980000 0.7348630000 0.7341760000 0.7345670000 -Thai Baht 0.0211936000 0.0211661000 0.0212042000 0.0211098000 -Trinidad And Tobago Dollar 0.1102220000 0.1092030000 -Tunisian Dinar 0.3225800000 0.3211100000 0.3215340000 0.3206630000 -U.A.E. Dirham 0.2019290000 0.2011190000 0.2012910000 0.2009580000 -Peso Uruguayo 0.0258745000 -Bolivar Fuerte 0.0743445000 0.0740462000 0.0741095000 0.0739869000 - -Currency units per SDR(3) - -Currency March 02, 2017 March 01, 2017 February 28, 2017 February 27, 2017 February 24, 2017 -Chinese Yuan 9.276350 9.300160 9.297740 9.309250 -Euro 1.280220 1.277620 1.277730 1.277200 -Japanese Yen 152.376000 152.381000 151.709000 152.909000 -U.K. Pound Sterling 1.094970 1.088340 1.089510 1.079530 -U.S. Dollar 1.348460 1.353890 1.352740 1.354980 -Algerian Dinar 148.971000 149.047000 148.939000 149.127000 -Australian Dollar 1.761310 1.761050 1.757940 1.755840 -Bahrain Dinar 0.507022 0.509064 0.508629 0.509471 -Botswana Pula 14.061100 14.059100 14.032500 14.026700 -Brazilian Real 4.178470 4.195300 4.191730 4.150570 -Brunei Dollar 1.897550 1.900870 1.900460 1.903340 -Canadian Dollar 1.793640 1.772220 1.775570 -Chilean Peso 874.990000 873.515000 873.408000 867.671000 -Colombian Peso 3,936.390000 3,921.250000 3,904.710000 3,891.050000 -Czech Koruna 34.593500 34.520300 34.524500 34.508600 -Danish Krone 9.516380 9.496770 9.497580 9.495140 -Hungarian Forint 393.643000 393.400000 393.592000 394.678000 -Icelandic Krona 143.611000 144.515000 145.541000 146.880000 -Indian Rupee 90.142100 90.355500 90.260900 -Indonesian Rupiah 18,016.800000 18,070.400000 18,044.200000 18,070.000000 -Iranian Rial 43,699.600000 43,870.200000 43,834.100000 -Israeli New Sheqel 4.897620 4.953900 4.976710 5.010720 -Kazakhstani Tenge 423.444000 422.690000 422.062000 -Korean Won 1,532.740000 1,529.950000 1,543.050000 -Kuwaiti Dinar 0.411955 0.413343 0.412991 0.413810 -Libyan Dinar 1.932400 1.932400 1.932400 1.932400 -Malaysian Ringgit 5.997290 6.018040 6.010190 6.024240 -Mauritian Rupee 47.967800 48.157700 48.152600 -Mexican Peso 27.072000 26.827800 26.874000 -Nepalese Rupee 144.016000 144.487000 144.648000 144.901000 -New Zealand Dollar 1.884900 1.885120 1.880110 1.875660 -Norwegian Krone 11.345100 11.331500 11.293100 11.285900 -Rial Omani 0.518484 0.520573 0.520126 0.520988 -Pakistani Rupee 141.377000 141.958000 141.839000 142.077000 -Nuevo Sol 4.412340 4.396400 4.402320 -Philippine Peso 67.766700 68.055900 67.903400 68.063300 -Polish Zloty 5.495770 5.519830 5.511740 5.512190 -Qatar Riyal 4.908410 4.928170 4.923970 4.932130 -Russian Ruble 78.719700 78.475100 78.373600 -Saudi Arabian Riyal 5.056740 5.077100 5.072770 5.081170 -Singapore Dollar 1.897550 1.900870 1.900460 1.903340 -South African Rand 17.606200 17.634300 17.546700 17.564000 -Sri Lanka Rupee 203.955000 204.776000 204.601000 -Swedish Krona 12.217300 12.239500 12.210300 12.157400 -Swiss Franc 1.362220 1.360800 1.362070 1.361350 -Thai Baht 47.184100 47.245400 47.160500 47.371400 -Trinidad And Tobago Dollar 9.072600 9.157260 -Tunisian Dinar 3.100010 3.114200 3.110090 3.118540 -U.A.E. Dirham 4.952240 4.972180 4.967930 4.976160 -Peso Uruguayo 38.648100 -Bolivar Fuerte 13.450900 13.505100 13.493500 13.515900 - - -(1) Exchange rates are published daily except on IMF holidays or whenever the IMF is closed for business. - -(2) The value of the U.S. dollar in terms of the SDR is the reciprocal of the sum of the dollar values, based on market exchange rates, of specified quantities of the SDR basket currencies. See SDR Valuation.The value in terms of the SDR of each of the other currencies shown above is derived from that currency's representative exchange rate against the U.S. dollar as reported by the issuing central bank and the SDR value of the U.S. dollar, except for the Iranian rial and the Libyan dinar, the values of which are officially expressed directly in terms of domestic currency units per SDR. All figures are rounded to six significant digits. See Representative Exchange Rates for Selected Currencies". - -(3) The value in terms of each national currency of the SDR is the reciprocal of the value in terms of the SDR of each national currency, rounded to six significant digits. \ No newline at end of file diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292 deleted file mode 100644 index e69de29bb2..0000000000 From e1d136368b53e40acc2cbc158d185f7794b40e3c Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 6 Mar 2017 18:04:28 +0100 Subject: [PATCH 050/291] BAEL-311 move jasypt to libraries module (#1309) * BEEL-311 move jasypt to libraries module * BAEL-9: README.md file updated (#1310) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * Guide to "when" block in Kotlin pull request (#1296) * Char array to string and string to char array test cases added * Minor code renames * Added groupingBy collector unit tests * Added test case for int summary calculation on grouped results * Added the grouping by classes to the main source path * Reverting char array to string test class * Reverting char array to string test class * Reverting char array to string test class * Reverting char array to string test class * Unit test class for Kotlin when block + required types * Minor changes to kotlin when block tests * Minor change * Minor change * Bael 655 (#1256) BAEL-655 hbase * Remove unnecessary files and update .gitignore (#1313) * BAEL-311 Removed jasypt module from parent pom (moved into libraries module) --- jasypt/pom.xml | 34 ---------------- libraries/pom.xml | 6 +++ .../java/com}/baeldung/jasypt/JasyptTest.java | 40 +++++++++---------- pom.xml | 1 - 4 files changed, 25 insertions(+), 56 deletions(-) delete mode 100644 jasypt/pom.xml rename {jasypt/src/test/java/org => libraries/src/test/java/com}/baeldung/jasypt/JasyptTest.java (66%) diff --git a/jasypt/pom.xml b/jasypt/pom.xml deleted file mode 100644 index 7e0c51f0b9..0000000000 --- a/jasypt/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - parent-modules - com.baeldung - 1.0.0-SNAPSHOT - - 4.0.0 - - jasypt - - - - org.jasypt - jasypt - ${jasypt.version} - - - junit - junit - ${junit.version} - test - - - - - 1.9.2 - 4.12 - - - - \ No newline at end of file diff --git a/libraries/pom.xml b/libraries/pom.xml index ee93ee934f..05f8dc47cf 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -31,6 +31,11 @@ cglib ${cglib.version} + + org.jasypt + jasypt + ${jasypt.version} + junit junit @@ -42,6 +47,7 @@ 3.2.4 4.12 + 1.9.2 diff --git a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java b/libraries/src/test/java/com/baeldung/jasypt/JasyptTest.java similarity index 66% rename from jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java rename to libraries/src/test/java/com/baeldung/jasypt/JasyptTest.java index c4bed5de83..fbfa7f823d 100644 --- a/jasypt/src/test/java/org/baeldung/jasypt/JasyptTest.java +++ b/libraries/src/test/java/com/baeldung/jasypt/JasyptTest.java @@ -1,4 +1,4 @@ -package org.baeldung.jasypt; +package com.baeldung.jasypt; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; @@ -8,27 +8,25 @@ import org.jasypt.util.text.BasicTextEncryptor; import org.junit.Ignore; import org.junit.Test; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotSame; -import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.*; import static junit.framework.TestCase.assertEquals; public class JasyptTest { @Test - public void givenTextPassword_whenDecrypt_thenCompareToEncrypted() { + public void givenTextPrivateData_whenDecrypt_thenCompareToEncrypted() { //given BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); - String password = "secret-pass"; - textEncryptor.setPasswordCharArray("some-random-password".toCharArray()); + String privateData = "secret-data"; + textEncryptor.setPasswordCharArray("some-random-data".toCharArray()); //when - String myEncryptedText = textEncryptor.encrypt(password); - assertNotSame(password, myEncryptedText); //myEncryptedText can be save in db + String myEncryptedText = textEncryptor.encrypt(privateData); + assertNotSame(privateData, myEncryptedText); //myEncryptedText can be save in db //then String plainText = textEncryptor.decrypt(myEncryptedText); - assertEquals(plainText, password); + assertEquals(plainText, privateData); } @Test @@ -61,38 +59,38 @@ public class JasyptTest { @Test @Ignore("should have installed local_policy.jar") - public void givenTextPassword_whenDecrypt_thenCompareToEncryptedWithCustomAlgorithm() { + public void givenTextPrivateData_whenDecrypt_thenCompareToEncryptedWithCustomAlgorithm() { //given StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); - String password = "secret-pass"; - encryptor.setPassword("secret-pass"); + String privateData = "secret-data"; + encryptor.setPassword("some-random-data"); encryptor.setAlgorithm("PBEWithMD5AndTripleDES"); //when String encryptedText = encryptor.encrypt("secret-pass"); - assertNotSame(password, encryptedText); + assertNotSame(privateData, encryptedText); //then String plainText = encryptor.decrypt(encryptedText); - assertEquals(plainText, password); + assertEquals(plainText, privateData); } @Test @Ignore("should have installed local_policy.jar") - public void givenTextPassword_whenDecryptOnHighPerformance_thenDecrypt(){ + public void givenTextPrivateData_whenDecryptOnHighPerformance_thenDecrypt(){ //given - String password = "secret-pass"; + String privateData = "secret-data"; PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); encryptor.setPoolSize(4); - encryptor.setPassword(password); + encryptor.setPassword("some-random-data"); encryptor.setAlgorithm("PBEWithMD5AndTripleDES"); //when - String encryptedText = encryptor.encrypt(password); - assertNotSame(password, encryptedText); + String encryptedText = encryptor.encrypt(privateData); + assertNotSame(privateData, encryptedText); //then String plainText = encryptor.decrypt(encryptedText); - assertEquals(plainText, password); + assertEquals(plainText, privateData); } } diff --git a/pom.xml b/pom.xml index 9c24200a0b..5230a680fe 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,6 @@ javaslang javax-servlets javaxval - jasypt jaxb jee7 jjwt From 4f51b3634f2437033559ccbd1802c764aec618e7 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Mon, 6 Mar 2017 18:25:12 +0100 Subject: [PATCH 051/291] Refactor Money and Currency API examples --- .../com/baeldung/money/JavaMoneyTest.java | 86 +++++++++++++++---- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index 3d2f986c30..d1992969f2 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -15,6 +15,8 @@ import javax.money.convert.MonetaryConversions; import javax.money.format.AmountFormatQueryBuilder; import javax.money.format.MonetaryAmountFormat; import javax.money.format.MonetaryFormats; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import static org.junit.Assert.*; @@ -40,7 +42,11 @@ public class JavaMoneyTest { @Test public void givenAmounts_whenStringified_thanEquals() { CurrencyUnit usd = Monetary.getCurrency("USD"); - MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(usd).setNumber(200).create(); + MonetaryAmount fstAmtUSD = Monetary + .getDefaultAmountFactory() + .setCurrency(usd) + .setNumber(200) + .create(); Money moneyof = Money.of(12, usd); FastMoney fastmoneyof = FastMoney.of(2, usd); @@ -52,7 +58,11 @@ public class JavaMoneyTest { @Test public void givenCurrencies_whenCompared_thanNotequal() { - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmount oneDolar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); Money oneEuro = Money.of(1, "EUR"); assertFalse(oneEuro.equals(FastMoney.of(1, "EUR"))); @@ -61,20 +71,22 @@ public class JavaMoneyTest { @Test(expected = ArithmeticException.class) public void givenAmount_whenDivided_thanThrowsException() { - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmount oneDolar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); oneDolar.divide(3); fail(); // if no exception } @Test public void givenAmounts_whenSummed_thanCorrect() { - MonetaryAmount[] monetaryAmounts = new MonetaryAmount[]{ - Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF")}; + List monetaryAmounts = Arrays.asList(Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF")); - Money sumAmtCHF = Money.of(0, "CHF"); - for (MonetaryAmount monetaryAmount : monetaryAmounts) { - sumAmtCHF = sumAmtCHF.add(monetaryAmount); - } + Money sumAmtCHF = (Money) monetaryAmounts + .stream() + .reduce(Money.of(0, "CHF"), MonetaryAmount::add); assertEquals("CHF 111.35", sumAmtCHF.toString()); } @@ -84,9 +96,19 @@ public class JavaMoneyTest { CurrencyUnit usd = Monetary.getCurrency("USD"); Money moneyof = Money.of(12, usd); - MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory().setCurrency(usd).setNumber(200.50).create(); - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); - Money subtractedAmount = Money.of(1, "USD").subtract(fstAmtUSD); + MonetaryAmount fstAmtUSD = Monetary + .getDefaultAmountFactory() + .setCurrency(usd) + .setNumber(200.50) + .create(); + MonetaryAmount oneDolar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); + Money subtractedAmount = Money + .of(1, "USD") + .subtract(fstAmtUSD); MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); MonetaryAmount divideAmount = oneDolar.divide(0.25); @@ -101,7 +123,11 @@ public class JavaMoneyTest { @Test public void givenAmount_whenRounded_thanEquals() { - MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + MonetaryAmount fstAmtEUR = Monetary + .getDefaultAmountFactory() + .setCurrency("EUR") + .setNumber(1.30473908) + .create(); MonetaryAmount roundEUR = fstAmtEUR.with(Monetary.getDefaultRounding()); assertEquals("EUR 1.30473908", fstAmtEUR.toString()); assertEquals("EUR 1.3", roundEUR.toString()); @@ -109,11 +135,19 @@ public class JavaMoneyTest { @Test public void givenAmount_whenCustomFormat_thanEquals() { - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); + MonetaryAmount oneDolar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); MonetaryAmountFormat formatUSD = MonetaryFormats.getAmountFormat(Locale.US); String usFormatted = formatUSD.format(oneDolar); - MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern", "00000.00 ¤").build()); + MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder + .of(Locale.US) + .set(CurrencyStyle.NAME) + .set("pattern", "00000.00 ¤") + .build()); String customFormatted = customFormat.format(oneDolar); assertEquals("USD 1", oneDolar.toString()); @@ -126,11 +160,25 @@ public class JavaMoneyTest { @Test public void givenAmount_whenConversion_thenNotNull() { CurrencyUnit USD = Monetary.getCurrency("USD"); - MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(1).create(); - MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory().setCurrency("EUR").setNumber(1.30473908).create(); + MonetaryAmount oneDolar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); + MonetaryAmount fstAmtEUR = Monetary + .getDefaultAmountFactory() + .setCurrency("EUR") + .setNumber(1.30473908) + .create(); - CurrencyConversion convEUR = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency("EUR").build()); - CurrencyConversion convUSD = MonetaryConversions.getConversion(ConversionQueryBuilder.of().setTermCurrency(USD).build()); + CurrencyConversion convEUR = MonetaryConversions.getConversion(ConversionQueryBuilder + .of() + .setTermCurrency("EUR") + .build()); + CurrencyConversion convUSD = MonetaryConversions.getConversion(ConversionQueryBuilder + .of() + .setTermCurrency(USD) + .build()); CurrencyConversion conversionUSD = MonetaryConversions.getConversion("USD"); CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR"); From f07985b402c96fbf54e4a05ae0a2f3c51fda47b8 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 6 Mar 2017 20:38:29 +0100 Subject: [PATCH 052/291] Remove spring-autowire (#1319) --- pom.xml | 1 - .../main/java/org/baeldung}/sample/App.java | 2 +- .../java/org/baeldung}/sample/AppConfig.java | 2 +- .../main/java/org/baeldung/sample/Bar.java | 5 + .../org/baeldung}/sample/BarFormatter.java | 2 +- .../main/java/org/baeldung/sample/Foo.java | 5 + .../main/java/org/baeldung/sample/FooDAO.java | 5 + .../org/baeldung}/sample/FooFormatter.java | 2 +- .../java/org/baeldung}/sample/FooService.java | 2 +- .../java/org/baeldung}/sample/Formatter.java | 2 +- .../org/baeldung}/sample/FormatterType.java | 2 +- .../sample/FooServiceIntegrationTest.java | 2 +- spring-autowire/README.md | 2 - spring-autowire/pom.xml | 105 ------------------ .../com/baeldung/autowire/sample/Bar.java | 5 - .../com/baeldung/autowire/sample/Foo.java | 5 - .../com/baeldung/autowire/sample/FooDAO.java | 5 - 17 files changed, 23 insertions(+), 131 deletions(-) rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/App.java (90%) rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/AppConfig.java (84%) create mode 100644 spring-all/src/main/java/org/baeldung/sample/Bar.java rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/BarFormatter.java (83%) create mode 100644 spring-all/src/main/java/org/baeldung/sample/Foo.java create mode 100644 spring-all/src/main/java/org/baeldung/sample/FooDAO.java rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/FooFormatter.java (83%) rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/FooService.java (88%) rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/Formatter.java (59%) rename {spring-autowire/src/main/java/com/baeldung/autowire => spring-all/src/main/java/org/baeldung}/sample/FormatterType.java (91%) rename {spring-autowire/src/test/java/com/baeldung/autowire => spring-all/src/test/java/org/baeldung}/sample/FooServiceIntegrationTest.java (94%) delete mode 100644 spring-autowire/README.md delete mode 100644 spring-autowire/pom.xml delete mode 100644 spring-autowire/src/main/java/com/baeldung/autowire/sample/Bar.java delete mode 100644 spring-autowire/src/main/java/com/baeldung/autowire/sample/Foo.java delete mode 100644 spring-autowire/src/main/java/com/baeldung/autowire/sample/FooDAO.java diff --git a/pom.xml b/pom.xml index 5230a680fe..5adbbcb7e3 100644 --- a/pom.xml +++ b/pom.xml @@ -111,7 +111,6 @@ spring-amqp spring-all spring-apache-camel - spring-autowire spring-batch spring-boot spring-cloud-data-flow diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/App.java b/spring-all/src/main/java/org/baeldung/sample/App.java similarity index 90% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/App.java rename to spring-all/src/main/java/org/baeldung/sample/App.java index 18ff11a49c..17fc49fc8c 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/App.java +++ b/spring-all/src/main/java/org/baeldung/sample/App.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.springframework.context.annotation.AnnotationConfigApplicationContext; diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/AppConfig.java b/spring-all/src/main/java/org/baeldung/sample/AppConfig.java similarity index 84% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/AppConfig.java rename to spring-all/src/main/java/org/baeldung/sample/AppConfig.java index f948e2bf8e..ffc792d9df 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/AppConfig.java +++ b/spring-all/src/main/java/org/baeldung/sample/AppConfig.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; diff --git a/spring-all/src/main/java/org/baeldung/sample/Bar.java b/spring-all/src/main/java/org/baeldung/sample/Bar.java new file mode 100644 index 0000000000..54e8d54418 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sample/Bar.java @@ -0,0 +1,5 @@ +package org.baeldung.sample; + +public class Bar { + +} diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/BarFormatter.java b/spring-all/src/main/java/org/baeldung/sample/BarFormatter.java similarity index 83% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/BarFormatter.java rename to spring-all/src/main/java/org/baeldung/sample/BarFormatter.java index e67a376d25..8396653970 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/BarFormatter.java +++ b/spring-all/src/main/java/org/baeldung/sample/BarFormatter.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.springframework.stereotype.Component; diff --git a/spring-all/src/main/java/org/baeldung/sample/Foo.java b/spring-all/src/main/java/org/baeldung/sample/Foo.java new file mode 100644 index 0000000000..562a00121a --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sample/Foo.java @@ -0,0 +1,5 @@ +package org.baeldung.sample; + +public class Foo { + +} diff --git a/spring-all/src/main/java/org/baeldung/sample/FooDAO.java b/spring-all/src/main/java/org/baeldung/sample/FooDAO.java new file mode 100644 index 0000000000..151c0c38de --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/sample/FooDAO.java @@ -0,0 +1,5 @@ +package org.baeldung.sample; + +public class FooDAO { + +} diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooFormatter.java b/spring-all/src/main/java/org/baeldung/sample/FooFormatter.java similarity index 83% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/FooFormatter.java rename to spring-all/src/main/java/org/baeldung/sample/FooFormatter.java index 57f93a53d7..68cb7f81f2 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooFormatter.java +++ b/spring-all/src/main/java/org/baeldung/sample/FooFormatter.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.springframework.stereotype.Component; diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooService.java b/spring-all/src/main/java/org/baeldung/sample/FooService.java similarity index 88% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/FooService.java rename to spring-all/src/main/java/org/baeldung/sample/FooService.java index c55d93da11..711711f205 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooService.java +++ b/spring-all/src/main/java/org/baeldung/sample/FooService.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Formatter.java b/spring-all/src/main/java/org/baeldung/sample/Formatter.java similarity index 59% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/Formatter.java rename to spring-all/src/main/java/org/baeldung/sample/Formatter.java index 59d718050a..ab29c2b848 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Formatter.java +++ b/spring-all/src/main/java/org/baeldung/sample/Formatter.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; public interface Formatter { diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FormatterType.java b/spring-all/src/main/java/org/baeldung/sample/FormatterType.java similarity index 91% rename from spring-autowire/src/main/java/com/baeldung/autowire/sample/FormatterType.java rename to spring-all/src/main/java/org/baeldung/sample/FormatterType.java index f2961745b5..d4d82dd022 100644 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FormatterType.java +++ b/spring-all/src/main/java/org/baeldung/sample/FormatterType.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/spring-autowire/src/test/java/com/baeldung/autowire/sample/FooServiceIntegrationTest.java b/spring-all/src/test/java/org/baeldung/sample/FooServiceIntegrationTest.java similarity index 94% rename from spring-autowire/src/test/java/com/baeldung/autowire/sample/FooServiceIntegrationTest.java rename to spring-all/src/test/java/org/baeldung/sample/FooServiceIntegrationTest.java index 34ba7902ca..6b518395a1 100644 --- a/spring-autowire/src/test/java/com/baeldung/autowire/sample/FooServiceIntegrationTest.java +++ b/spring-all/src/test/java/org/baeldung/sample/FooServiceIntegrationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.autowire.sample; +package org.baeldung.sample; import org.junit.Assert; import org.junit.Test; diff --git a/spring-autowire/README.md b/spring-autowire/README.md deleted file mode 100644 index d5b8221b25..0000000000 --- a/spring-autowire/README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Relevant Articles: -- [Guide to Spring @Autowired](http://www.baeldung.com/spring-autowire) diff --git a/spring-autowire/pom.xml b/spring-autowire/pom.xml deleted file mode 100644 index 391cfc018e..0000000000 --- a/spring-autowire/pom.xml +++ /dev/null @@ -1,105 +0,0 @@ - - 4.0.0 - - com.baeldung - spring-autowire - 0.0.1-SNAPSHOT - jar - - spring-autowire - http://maven.apache.org - - - UTF-8 - 4.3.4.RELEASE - 4.12 - 3.6.0 - 2.19.1 - - - - - junit - junit - ${junit.version} - - - org.springframework - spring-core - ${org.springframework.version} - - - org.springframework - spring-context - ${org.springframework.version} - - - org.springframework - spring-test - ${org.springframework.version} - test - - - - - spring-autowire - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - **/*IntegrationTest.java - **/*LiveTest.java - - - - - - - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - - diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Bar.java b/spring-autowire/src/main/java/com/baeldung/autowire/sample/Bar.java deleted file mode 100644 index 7aa820adef..0000000000 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Bar.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.autowire.sample; - -public class Bar { - -} diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Foo.java b/spring-autowire/src/main/java/com/baeldung/autowire/sample/Foo.java deleted file mode 100644 index b587ab38b8..0000000000 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/Foo.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.autowire.sample; - -public class Foo { - -} diff --git a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooDAO.java b/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooDAO.java deleted file mode 100644 index aec26202ab..0000000000 --- a/spring-autowire/src/main/java/com/baeldung/autowire/sample/FooDAO.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.autowire.sample; - -public class FooDAO { - -} From 7a92909566d22741748d0a9c4303dcfc8af76ed0 Mon Sep 17 00:00:00 2001 From: Yasin Date: Tue, 7 Mar 2017 01:28:33 +0530 Subject: [PATCH 053/291] BAEL-608 - Introduction to Java9 StackWalking API (#1315) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" --- .../java9/stackwalker/StackWalkerDemo.java | 64 +++++++++++++++++++ .../stackwalker/StackWalkerDemoTest.java | 11 ++++ 2 files changed, 75 insertions(+) create mode 100644 core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java create mode 100644 core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java b/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java new file mode 100644 index 0000000000..ee2cf092cd --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java @@ -0,0 +1,64 @@ +package com.baeldung.java9.stackwalker; + +import java.lang.StackWalker.StackFrame; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class StackWalkerDemo { + + public void methodOne() { + this.methodTwo(); + } + + public void methodTwo() { + this.methodThree(); + } + + public void methodThree() { + List stackTrace = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) + .walk(StackWalkerDemo::walkExample); + + printStackTrace(stackTrace); + + System.out.println("---------------------------------------------"); + + stackTrace = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) + .walk(StackWalkerDemo::walkExample2); + + printStackTrace(stackTrace); + + System.out.println("---------------------------------------------"); + + String line = StackWalker.getInstance() + .walk(StackWalkerDemo::walkExample3); + System.out.println(line); + } + + private static List walkExample(Stream stackFrameStream) { + return stackFrameStream.collect(Collectors.toList()); + } + + private static List walkExample2(Stream stackFrameStream) { + return stackFrameStream.filter(frame -> frame.getClassName() + .contains("com.baeldung")) + .collect(Collectors.toList()); + } + + private static String walkExample3(Stream stackFrameStream) { + return stackFrameStream.filter(frame -> frame.getClassName() + .contains("com.baeldung") + && frame.getClassName() + .endsWith("Test")) + .findFirst() + .map(frame -> frame.getClassName() + "#" + frame.getMethodName() + ", Line " + frame.getLineNumber()) + .orElse("Unknown caller"); + } + + private void printStackTrace(List stackTrace) { + for (StackFrame stackFrame : stackTrace) { + System.out.println(stackFrame.getDeclaringClass() + .toString() + "#" + stackFrame.getMethodName() + ", Line " + stackFrame.getLineNumber()); + } + } +} diff --git a/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java b/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java new file mode 100644 index 0000000000..61c8440b87 --- /dev/null +++ b/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java @@ -0,0 +1,11 @@ +package com.baeldung.java9.stackwalker; + +import org.junit.Test; + +public class StackWalkerDemoTest { + + @Test + public void walkTheStack() { + new StackWalkerDemo().methodOne(); + } +} From 7355266feb70e1400d0556a230f42ded3824ef5d Mon Sep 17 00:00:00 2001 From: Saptarshi Basu Date: Tue, 7 Mar 2017 02:38:01 +0530 Subject: [PATCH 054/291] BAEL-705: spring-ldap code (#1299) * WatchService vs. Apache Commons IO Mnitoring * Indentation fixed * Indentation fixed * JAX-RS API using Jersey [BAEL-558] * JAX-RS API using Jersey [BAEL-558] * Modifications made to remove xml * applicationContext.xml removed * All try catch moved to ExceptionMapper * fixes * review comments incorporated * module renamed * JAX-RS client [BAEL-595] * jersey-core dependency removed * assert changed to assertEquals * messagebody readers and writers removed * pom dependency corrected and other minor changes * Jersey version changed and toString() changed to valueOf() * BAEL-705: Spring Ldap code * BAEL-705: Spring Ldap code tab prob rectified * BAEL-705: Spring Ldap code, readme fixed * review comments incorporated --- pom.xml | 1 + spring-ldap/.gitignore | 13 ++ spring-ldap/README.md | 5 + spring-ldap/pom.xml | 181 ++++++++++++++++++ .../com/baeldung/ldap/client/LdapClient.java | 80 ++++++++ .../baeldung/ldap/javaconfig/AppConfig.java | 44 +++++ .../src/main/resources/application.properties | 6 + spring-ldap/src/main/resources/logback.xml | 15 ++ .../ldap/client/LdapClientLiveTest.java | 63 ++++++ .../baeldung/ldap/javaconfig/TestConfig.java | 59 ++++++ spring-ldap/src/test/resources/test.ldif | 24 +++ .../resources/test_application.properties | 7 + 12 files changed, 498 insertions(+) create mode 100644 spring-ldap/.gitignore create mode 100644 spring-ldap/README.md create mode 100644 spring-ldap/pom.xml create mode 100644 spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java create mode 100644 spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java create mode 100644 spring-ldap/src/main/resources/application.properties create mode 100644 spring-ldap/src/main/resources/logback.xml create mode 100644 spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java create mode 100644 spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java create mode 100644 spring-ldap/src/test/resources/test.ldif create mode 100644 spring-ldap/src/test/resources/test_application.properties diff --git a/pom.xml b/pom.xml index 5adbbcb7e3..9243770060 100644 --- a/pom.xml +++ b/pom.xml @@ -137,6 +137,7 @@ spring-jooq spring-jpa spring-katharsis + spring-ldap spring-mockito spring-mvc-email spring-mvc-forms diff --git a/spring-ldap/.gitignore b/spring-ldap/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/spring-ldap/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/spring-ldap/README.md b/spring-ldap/README.md new file mode 100644 index 0000000000..56ffdee617 --- /dev/null +++ b/spring-ldap/README.md @@ -0,0 +1,5 @@ +========= + +## Spring LDAP Example Project +- (http://www.baeldung.com/spring-ldap-overview/) + diff --git a/spring-ldap/pom.xml b/spring-ldap/pom.xml new file mode 100644 index 0000000000..55014897c4 --- /dev/null +++ b/spring-ldap/pom.xml @@ -0,0 +1,181 @@ + + + 4.0.0 + + com.baeldung + spring-ldap + 0.1-SNAPSHOT + jar + + + 4.12 + 2.19.1 + 3.6.1 + 2.3.1.RELEASE + 1.7.22 + 1.1.8 + 4.3.6.RELEASE + 1.5.5 + 0.9.15 + 1.3 + + + + spring-ldap + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + + org.springframework.ldap + spring-ldap-core + ${spring-ldap.version} + + + commons-logging + commons-logging + + + + + + org.slf4j + jcl-over-slf4j + ${jcl.slf4j.version} + + + + ch.qos.logback + logback-classic + ${logback.version} + + + org.springframework + spring-context + ${spring-context.version} + + + + + + + junit + junit + ${junit.version} + test + + + + org.hamcrest + hamcrest-core + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-library + ${org.hamcrest.version} + test + + + + + org.springframework.ldap + spring-ldap-test + ${spring-ldap.version} + test + + + + + org.apache.directory.server + apacheds-core + ${apacheds.version} + test + + + org.apache.directory.server + apacheds-core-entry + ${apacheds.version} + test + + + org.apache.directory.server + apacheds-protocol-shared + ${apacheds.version} + test + + + org.apache.directory.server + apacheds-protocol-ldap + ${apacheds.version} + test + + + org.apache.directory.server + apacheds-server-jndi + ${apacheds.version} + test + + + org.apache.directory.shared + shared-ldap + ${shared-ldap.version} + test + + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*IntegrationTest.java + + + **/*LiveTest.java + + + + + + + + + + \ No newline at end of file diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java new file mode 100644 index 0000000000..8c71007b27 --- /dev/null +++ b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java @@ -0,0 +1,80 @@ +package com.baeldung.ldap.client; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.List; + +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.ldap.core.AttributesMapper; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.support.LdapNameBuilder; + +public class LdapClient { + + @Autowired + private Environment env; + + @Autowired + private ContextSource contextSource; + + @Autowired + private LdapTemplate ldapTemplate; + + public void authenticate(final String username, final String password) { + contextSource.getContext("cn=" + username + ",ou=users," + env.getRequiredProperty("ldap.partitionSuffix"), password); + } + + public List search(final String username) { + List users = ldapTemplate.search("ou=users", "cn=" + username, new AttributesMapper() { + public String mapFromAttributes(Attributes attrs) throws NamingException { + return (String) attrs.get("cn").get(); + } + }); + return users; + } + + public void create(final String username, final String password) { + Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build(); + DirContextAdapter context = new DirContextAdapter(dn); + + context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" }); + context.setAttributeValue("cn", username); + context.setAttributeValue("sn", username); + context.setAttributeValue("userPassword", digestSHA(password)); + + ldapTemplate.bind(context); + } + + public void modify(final String username, final String password) { + Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build(); + DirContextOperations context = ldapTemplate.lookupContext(dn); + + context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" }); + context.setAttributeValue("cn", username); + context.setAttributeValue("sn", username); + context.setAttributeValue("userPassword", digestSHA(password)); + + ldapTemplate.modifyAttributes(context); + } + + private String digestSHA(final String password) { + String base64; + try { + MessageDigest digest = MessageDigest.getInstance("SHA"); + digest.update(password.getBytes()); + base64 = Base64.getEncoder().encodeToString(digest.digest()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + return "{SHA}" + base64; + } +} diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java new file mode 100644 index 0000000000..8572e5d1be --- /dev/null +++ b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java @@ -0,0 +1,44 @@ +package com.baeldung.ldap.javaconfig; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.LdapContextSource; + +import com.baeldung.ldap.client.LdapClient; + +@Configuration +@PropertySource("classpath:application.properties") +@ComponentScan(basePackages = { "com.baeldung.ldap.*" }) +@Profile("default") +public class AppConfig { + + @Autowired + private Environment env; + + @Bean + public LdapContextSource contextSource() { + LdapContextSource contextSource = new LdapContextSource(); + contextSource.setUrl(env.getRequiredProperty("ldap.url")); + contextSource.setBase(env.getRequiredProperty("ldap.partitionSuffix")); + contextSource.setUserDn(env.getRequiredProperty("ldap.principal")); + contextSource.setPassword(env.getRequiredProperty("ldap.password")); + return contextSource; + } + + @Bean + public LdapTemplate ldapTemplate() { + return new LdapTemplate(contextSource()); + } + + @Bean + public LdapClient ldapClient() { + return new LdapClient(); + } + +} diff --git a/spring-ldap/src/main/resources/application.properties b/spring-ldap/src/main/resources/application.properties new file mode 100644 index 0000000000..670fb79234 --- /dev/null +++ b/spring-ldap/src/main/resources/application.properties @@ -0,0 +1,6 @@ +ldap.partitionSuffix=dc=example,dc=com +ldap.partition=example +ldap.principal=uid=admin,ou=system +ldap.password=secret +ldap.port=18889 +ldap.url=ldap://localhost:18889 \ No newline at end of file diff --git a/spring-ldap/src/main/resources/logback.xml b/spring-ldap/src/main/resources/logback.xml new file mode 100644 index 0000000000..788096686a --- /dev/null +++ b/spring-ldap/src/main/resources/logback.xml @@ -0,0 +1,15 @@ + + + + + web - %date [%thread] %-5level %logger{36} - + %message%n + + + + + + + + + \ No newline at end of file diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java new file mode 100644 index 0000000000..b65588dc38 --- /dev/null +++ b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java @@ -0,0 +1,63 @@ +package com.baeldung.ldap.client; + +import java.util.List; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ldap.AuthenticationException; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import com.baeldung.ldap.javaconfig.TestConfig; + +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles("testlive") +@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class) +public class LdapClientLiveTest { + + private static final String USER2 = "TEST02"; + private static final String USER3 = "TEST03"; + private static final String USER4 = "TEST04"; + + private static final String USER2_PWD = "TEST02"; + private static final String USER3_PWD = "TEST03"; + private static final String USER4_PWD = "TEST04"; + + private static final String SEARCH_STRING = "TEST*"; + + @Autowired + private LdapClient ldapClient; + + @Test + public void givenLdapClient_whenCorrectCredentials_thenSuccessfulLogin() { + ldapClient.authenticate(USER3, USER3_PWD); + } + + @Test(expected = AuthenticationException.class) + public void givenLdapClient_whenIncorrectCredentials_thenFailedLogin() { + ldapClient.authenticate(USER3, USER2_PWD); + } + + @Test + public void givenLdapClient_whenCorrectSearchFilter_thenEntriesReturned() { + List users = ldapClient.search(SEARCH_STRING); + Assert.assertThat(users, Matchers.containsInAnyOrder(USER2, USER3)); + } + + @Test + public void givenLdapClientNotExists_whenDataProvided_thenNewUserCreated() { + ldapClient.create(USER4, USER4_PWD); + ldapClient.authenticate(USER4, USER4_PWD); + } + + @Test + public void givenLdapClientExists_whenDataProvided_thenExistingUserModified() { + ldapClient.modify(USER2, USER3_PWD); + ldapClient.authenticate(USER2, USER3_PWD); + } +} diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java new file mode 100644 index 0000000000..e2968e977c --- /dev/null +++ b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java @@ -0,0 +1,59 @@ +package com.baeldung.ldap.javaconfig; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.ldap.test.TestContextSourceFactoryBean; + +import com.baeldung.ldap.client.LdapClient; + +@Configuration +@PropertySource("classpath:test_application.properties") +@ComponentScan(basePackages = { "com.baeldung.ldap.*" }) +@Profile("testlive") +public class TestConfig { + @Autowired + private Environment env; + + @Autowired + private ResourceLoader resourceLoader; + + @Bean + public TestContextSourceFactoryBean testContextSource() { + TestContextSourceFactoryBean contextSource = new TestContextSourceFactoryBean(); + contextSource.setDefaultPartitionName(env.getRequiredProperty("ldap.partition")); + contextSource.setDefaultPartitionSuffix(env.getRequiredProperty("ldap.partitionSuffix")); + contextSource.setPrincipal(env.getRequiredProperty("ldap.principal")); + contextSource.setPassword(env.getRequiredProperty("ldap.password")); + contextSource.setLdifFile(resourceLoader.getResource(env.getRequiredProperty("ldap.ldiffile"))); + contextSource.setPort(Integer.valueOf(env.getRequiredProperty("ldap.port"))); + return contextSource; + } + + @Bean + public LdapContextSource contextSource() { + LdapContextSource contextSource = new LdapContextSource(); + contextSource.setUrl(env.getRequiredProperty("ldap.url")); + contextSource.setBase(env.getRequiredProperty("ldap.partitionSuffix")); + contextSource.setUserDn(env.getRequiredProperty("ldap.principal")); + contextSource.setPassword(env.getRequiredProperty("ldap.password")); + return contextSource; + } + + @Bean + public LdapTemplate ldapTemplate() { + return new LdapTemplate(contextSource()); + } + + @Bean + public LdapClient ldapClient() { + return new LdapClient(); + } +} diff --git a/spring-ldap/src/test/resources/test.ldif b/spring-ldap/src/test/resources/test.ldif new file mode 100644 index 0000000000..2344630204 --- /dev/null +++ b/spring-ldap/src/test/resources/test.ldif @@ -0,0 +1,24 @@ +version: 1 +dn: ou=users,dc=example,dc=com +objectClass: organizationalUnit +objectClass: top +ou: users + +dn: cn=TEST03,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +objectClass: top +cn: TEST03 +sn: TEST03 +userPassword:: e1NIQX1JbktFOFY2enBpWWdMY0RYQTYzdXZVNjRGZXc9 + +dn: cn=TEST02,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +objectClass: top +cn: TEST02 +sn: TEST02 +userPassword:: e1NIQX1uZERKdWNNYnl5a3hWdEkyQzgyRUFlalN1WTQ9 + diff --git a/spring-ldap/src/test/resources/test_application.properties b/spring-ldap/src/test/resources/test_application.properties new file mode 100644 index 0000000000..40b90cfdcf --- /dev/null +++ b/spring-ldap/src/test/resources/test_application.properties @@ -0,0 +1,7 @@ +ldap.partitionSuffix=dc=example,dc=com +ldap.partition=example +ldap.principal=uid=admin,ou=system +ldap.password=secret +ldap.ldiffile=classpath:/test.ldif +ldap.port=18888 +ldap.url=ldap://localhost:18888 \ No newline at end of file From 22842a0e718c35465cc4616a53859fa5f38b3780 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 6 Mar 2017 22:41:34 +0100 Subject: [PATCH 055/291] Update README.md (#1321) --- spring-all/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-all/README.md b/spring-all/README.md index a8ea7c58c7..047f1bd5f6 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -8,6 +8,7 @@ This project is used to replicate Spring Exceptions only. The "REST With Spring" Classes: http://bit.ly/restwithspring ### Relevant articles: +- [Guide to Spring @Autowired](http://www.baeldung.com/spring-autowire) - [Properties with Spring](http://www.baeldung.com/2012/02/06/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage - [Spring Profiles](http://www.baeldung.com/spring-profiles) - [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor) From f57af2b200fcf8089dd026d1d7ec0516bb250df7 Mon Sep 17 00:00:00 2001 From: nguyennamthai Date: Tue, 7 Mar 2017 06:19:27 +0700 Subject: [PATCH 056/291] Move Commons Lang to the libraries module (#1311) * Introduction to Apache Commons Lang 3 * Move Commons Lang to the libraries module * Update pom.xml * Update pom.xml --- apache-commons/pom.xml | 36 ------------------- libraries/pom.xml | 16 ++++++--- .../commons/lang3/ArrayUtilsTest.java | 0 .../commons/lang3/StringUtilsTest.java | 0 4 files changed, 11 insertions(+), 41 deletions(-) delete mode 100644 apache-commons/pom.xml rename {apache-commons => libraries}/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java (100%) rename {apache-commons => libraries}/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java (100%) diff --git a/apache-commons/pom.xml b/apache-commons/pom.xml deleted file mode 100644 index 6e5c2065db..0000000000 --- a/apache-commons/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - 4.0.0 - com.baeldung - apache-commons - 0.0.1-SNAPSHOT - - 4.12 - 3.6.0 - - - - - maven-compiler-plugin - ${compiler.version} - - 1.8 - 1.8 - - - - - - - org.apache.commons - commons-lang3 - 3.5 - - - junit - junit - ${junit.version} - test - - - \ No newline at end of file diff --git a/libraries/pom.xml b/libraries/pom.xml index 05f8dc47cf..bfcc9b66d5 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -32,9 +32,9 @@ ${cglib.version} - org.jasypt - jasypt - ${jasypt.version} + org.apache.commons + commons-lang3 + ${commons-lang.version} junit @@ -42,13 +42,19 @@ ${junit.version} test + + org.jasypt + jasypt + ${jasypt.version} + + 3.2.4 + 3.5 4.12 1.9.2 - - \ No newline at end of file + diff --git a/apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java b/libraries/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java similarity index 100% rename from apache-commons/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java rename to libraries/src/test/java/com/baeldung/commons/lang3/ArrayUtilsTest.java diff --git a/apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java b/libraries/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java similarity index 100% rename from apache-commons/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java rename to libraries/src/test/java/com/baeldung/commons/lang3/StringUtilsTest.java From 42ab31718818c1e9effbee9460c677f396f66a6f Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Tue, 7 Mar 2017 21:15:18 +0530 Subject: [PATCH 057/291] BAEL-701 updated the method argument --- .../java/com/baeldung/reports/CustomisedListener.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testng/src/test/java/com/baeldung/reports/CustomisedListener.java b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java index e8338c941d..6dc3991e50 100644 --- a/testng/src/test/java/com/baeldung/reports/CustomisedListener.java +++ b/testng/src/test/java/com/baeldung/reports/CustomisedListener.java @@ -10,22 +10,22 @@ public class CustomisedListener implements ITestListener { private static final Logger LOGGER = LoggerFactory.getLogger("TEST_REPORT"); @Override - public void onFinish(ITestContext arg0) { + public void onFinish(ITestContext context) { LOGGER.info("PASSED TEST CASES"); - arg0.getPassedTests() + context.getPassedTests() .getAllResults() .stream() .forEach(result -> { LOGGER.info(result.getName()); }); LOGGER.info("FAILED TEST CASES"); - arg0.getFailedTests() + context.getFailedTests() .getAllResults() .stream() .forEach(result -> { LOGGER.info(result.getName()); }); - LOGGER.info("Test completed on: " + arg0.getEndDate().toString()); + LOGGER.info("Test completed on: " + context.getEndDate().toString()); } @Override From 6fbf90fd27f0072df1716c7a624b68105ba00287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20G=C3=B3mez?= Date: Tue, 7 Mar 2017 09:55:22 -0600 Subject: [PATCH 058/291] [BAEL-694] Hibernate immutable annotation (#1302) * Add project for hibernate immutable article Add Event entity Add hibernate configuration file Add hibernateutil for configuration Add test to match snippets from article * Create README.md * Update README.md --- hibernate-immutable/README.md | 2 + hibernate-immutable/pom.xml | 30 +++++++ .../java/com/baeldung/entities/Event.java | 52 +++++++++++++ .../java/com/baeldung/util/HibernateUtil.java | 29 +++++++ .../src/main/resources/hibernate.cfg.xml | 38 +++++++++ .../src/test/java/EventTest.java | 78 +++++++++++++++++++ 6 files changed, 229 insertions(+) create mode 100644 hibernate-immutable/README.md create mode 100644 hibernate-immutable/pom.xml create mode 100644 hibernate-immutable/src/main/java/com/baeldung/entities/Event.java create mode 100644 hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java create mode 100644 hibernate-immutable/src/main/resources/hibernate.cfg.xml create mode 100644 hibernate-immutable/src/test/java/EventTest.java diff --git a/hibernate-immutable/README.md b/hibernate-immutable/README.md new file mode 100644 index 0000000000..f564d8fc3f --- /dev/null +++ b/hibernate-immutable/README.md @@ -0,0 +1,2 @@ +Article +- [Guide to @Immutable Annotation in Hibernate](http://inprogress.baeldung.com/?p=35824&preview=true) diff --git a/hibernate-immutable/pom.xml b/hibernate-immutable/pom.xml new file mode 100644 index 0000000000..f4ed2d3cf4 --- /dev/null +++ b/hibernate-immutable/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + com.baeldung + hibernate-immutable + 1.0-SNAPSHOT + + + + org.hibernate + hibernate-core + 4.3.10.Final + + + org.hsqldb + hsqldb + 2.2.9 + + + junit + junit + 4.11 + test + + + + \ No newline at end of file diff --git a/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java b/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java new file mode 100644 index 0000000000..a8690a8959 --- /dev/null +++ b/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java @@ -0,0 +1,52 @@ +package com.baeldung.entities; + +import org.hibernate.annotations.*; +import org.hibernate.annotations.CascadeType; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.Set; + +@Entity +@Immutable +@Table(name = "events") +public class Event { + @Id + @Column(name = "event_id") + @GeneratedValue(generator = "increment") + @GenericGenerator(name = "increment", strategy = "increment") + private Long id; + + @Column(name = "title") + private String title; + + @ElementCollection + @Immutable + private Set guestList; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) + public Set getGuestList() { + return guestList; + } + + public void setGuestList(Set guestList) { + this.guestList = guestList; + } +} diff --git a/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java b/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java new file mode 100644 index 0000000000..f802342b86 --- /dev/null +++ b/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java @@ -0,0 +1,29 @@ +package com.baeldung.util; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.service.ServiceRegistry; + +public class HibernateUtil { + private static final SessionFactory sessionFactory = buildSessionFactory(); + + private static SessionFactory buildSessionFactory() { + try { + // Create a session factory from hibernate.cfg.xml + Configuration configuration = new Configuration(); + configuration.configure("hibernate.cfg.xml"); + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + return configuration.buildSessionFactory(serviceRegistry); + } catch (Throwable ex) { + System.out.println("Initial SessionFactory creation failed." + ex); + throw new ExceptionInInitializerError(ex); + } + } + + public static SessionFactory getSessionFactory() { + return sessionFactory; + } +} diff --git a/hibernate-immutable/src/main/resources/hibernate.cfg.xml b/hibernate-immutable/src/main/resources/hibernate.cfg.xml new file mode 100644 index 0000000000..756191a9e2 --- /dev/null +++ b/hibernate-immutable/src/main/resources/hibernate.cfg.xml @@ -0,0 +1,38 @@ + + + + + + + + + org.hsqldb.jdbcDriver + jdbc:hsqldb:hsql://localhost/xdb + sa + + + + 1 + + + org.hibernate.dialect.HSQLDialect + + + thread + + + org.hibernate.cache.NoCacheProvider + + + true + + + update + + + + + + \ No newline at end of file diff --git a/hibernate-immutable/src/test/java/EventTest.java b/hibernate-immutable/src/test/java/EventTest.java new file mode 100644 index 0000000000..f05aaff5f5 --- /dev/null +++ b/hibernate-immutable/src/test/java/EventTest.java @@ -0,0 +1,78 @@ +import com.baeldung.entities.Event; +import com.baeldung.util.HibernateUtil; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import javax.persistence.Table; + +public class EventTest { + + private Session session; + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Before + public void setup() { + session = HibernateUtil.getSessionFactory().getCurrentSession(); + session.beginTransaction(); + } + + @After + public void teardown() { + HibernateUtil.getSessionFactory().close(); + } + + @Test + public void addEvent() { + Event event = new Event(); + event.setTitle("Public Event"); + session.save(event); + session.getTransaction().commit(); + } + + @Test + public void updateEvent() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='My Event'").list().get(0); + event.setTitle("Public Event"); + session.saveOrUpdate(event); + session.getTransaction().commit(); + } + + @Test + public void deleteEvent() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='My Event'").list().get(0); + session.delete(event); + session.getTransaction().commit(); + } + + @Test + public void addGuest() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='Public Event'").list().get(0); + String newGuest = "Sara"; + event.getGuestList().add(newGuest); + + exception.expect(HibernateException.class); + session.save(event); + session.getTransaction().commit(); + } + + @Test + public void deleteCascade() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='Public Event'").list().get(0); + String guest = event.getGuestList().iterator().next(); + event.getGuestList().remove(guest); + + exception.expect(HibernateException.class); + session.saveOrUpdate(event); + session.getTransaction().commit(); + } +} From a7bafc07758bee1d14929edffbdd26c07ddbc072 Mon Sep 17 00:00:00 2001 From: Ahmed-Saied Date: Tue, 7 Mar 2017 18:01:44 +0200 Subject: [PATCH 059/291] spring boot test (#1322) * spring boot test * testing in spring boot article --- spring-boot/pom.xml | 6 ++ .../boot/components/FooComponent.java | 58 ++++++++++++++++ .../boot/exceptions/CommonException.java | 13 ++++ .../boot/exceptions/FooNotFoundException.java | 13 ++++ .../java/org/baeldung/boot/model/Foo.java | 7 ++ .../org/baeldung/boot/service/FooService.java | 52 ++++++++++++++ .../org/baeldung/boot/FooComponentTests.java | 68 +++++++++++++++++++ .../org/baeldung/boot/FooIntegrationTest.java | 43 ++++++++++++ .../java/org/baeldung/boot/FooJPATest.java | 34 ++++++++++ .../java/org/baeldung/boot/FooJsonTest.java | 35 ++++++++++ .../src/test/resources/application.properties | 4 +- spring-boot/src/test/resources/import.sql | 1 + .../resources/org/baeldung/boot/expected.json | 4 ++ 13 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java create mode 100644 spring-boot/src/main/java/org/baeldung/boot/exceptions/CommonException.java create mode 100644 spring-boot/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java create mode 100644 spring-boot/src/main/java/org/baeldung/boot/service/FooService.java create mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java create mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java create mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java create mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java create mode 100644 spring-boot/src/test/resources/import.sql create mode 100644 spring-boot/src/test/resources/org/baeldung/boot/expected.json diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 65b0f247f8..7a305322a6 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -106,6 +106,12 @@ ${jquery.version} + + com.google.guava + guava + 18.0 + + org.apache.tomcat tomcat-servlet-api diff --git a/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java b/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java new file mode 100644 index 0000000000..b327958c16 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java @@ -0,0 +1,58 @@ +package org.baeldung.boot.components; + +import org.baeldung.boot.exceptions.CommonException; +import org.baeldung.boot.exceptions.FooNotFoundException; +import org.baeldung.boot.model.Foo; +import org.baeldung.boot.repository.FooRepository; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.common.base.Preconditions; + +@Component +public class FooComponent { + + @Autowired + private FooRepository fooRepository; + + private final static Logger logger = org.slf4j.LoggerFactory.getLogger(FooComponent.class); + + public Foo getFooWithId(Integer id) { + + Foo foo = null; + + try { + foo = fooRepository.findOne(id); + Preconditions.checkNotNull(foo); + logger.info("Foo with Id {} found",id); + }catch(NullPointerException ex){ + logger.error("Foo with Id {} was not found",id); + throw new FooNotFoundException("The given foo Id was not found"); + } catch (Exception ex) { + logger.error("Error while retrieving Foo with Id {} found",id,ex); + throw new CommonException("Error while retrieving foo"); + } + + return foo; + } + + public Foo getFooWithName(String name) { + + Foo foo = null; + + try { + foo = fooRepository.findByName(name); + Preconditions.checkNotNull(foo); + logger.info("Foo with name {} found",name); + }catch(NullPointerException ex){ + logger.error("Foo with name {} was not found",name); + throw new FooNotFoundException("The given foo name was not found"); + } catch (Exception ex) { + logger.error("Error while retrieving Foo with name {} found",name,ex); + throw new CommonException("Error while retrieving foo"); + } + + return foo; + } +} \ No newline at end of file diff --git a/spring-boot/src/main/java/org/baeldung/boot/exceptions/CommonException.java b/spring-boot/src/main/java/org/baeldung/boot/exceptions/CommonException.java new file mode 100644 index 0000000000..1f008440e6 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/exceptions/CommonException.java @@ -0,0 +1,13 @@ +package org.baeldung.boot.exceptions; + +public class CommonException extends RuntimeException{ + + /** + * + */ + private static final long serialVersionUID = 3080004140659213332L; + + public CommonException(String message){ + super(message); + } +} diff --git a/spring-boot/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java b/spring-boot/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java new file mode 100644 index 0000000000..68ef3fa389 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java @@ -0,0 +1,13 @@ +package org.baeldung.boot.exceptions; + +public class FooNotFoundException extends RuntimeException{ + + /** + * + */ + private static final long serialVersionUID = 9042200028456133589L; + + public FooNotFoundException(String message){ + super(message); + } +} diff --git a/spring-boot/src/main/java/org/baeldung/boot/model/Foo.java b/spring-boot/src/main/java/org/baeldung/boot/model/Foo.java index 6a36459e3c..ac8a8fe429 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/model/Foo.java +++ b/spring-boot/src/main/java/org/baeldung/boot/model/Foo.java @@ -21,6 +21,13 @@ public class Foo implements Serializable { this.name = name; } + + public Foo(Integer id, String name) { + super(); + this.id = id; + this.name = name; + } + public Integer getId() { return id; } diff --git a/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java b/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java new file mode 100644 index 0000000000..2cb64ea139 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java @@ -0,0 +1,52 @@ +package org.baeldung.boot.service; + +import org.baeldung.boot.components.FooComponent; +import org.baeldung.boot.exceptions.CommonException; +import org.baeldung.boot.exceptions.FooNotFoundException; +import org.baeldung.boot.model.Foo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class FooService { + + @Autowired + private FooComponent fooComponent; + + @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getFooWithId(@PathVariable Integer id) { + + Foo foo = fooComponent.getFooWithId(id); + + return new ResponseEntity(foo, HttpStatus.OK); + } + + @RequestMapping(value = "/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getFooWithName(@RequestParam String name) { + + Foo foo = fooComponent.getFooWithName(name); + + return new ResponseEntity(foo, HttpStatus.OK); + } + + @ExceptionHandler(value = FooNotFoundException.class) + @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Foo not found") + public void handleFooNotFoundException() { + + } + + @ExceptionHandler(value = CommonException.class) + @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Common exception") + public void handleCommonException() { + + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java new file mode 100644 index 0000000000..775f7c1ef0 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java @@ -0,0 +1,68 @@ +package org.baeldung.boot; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; + +import java.util.HashMap; +import java.util.Map; + +import org.baeldung.boot.components.FooComponent; +import org.baeldung.boot.model.Foo; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class FooComponentTests { + + @Autowired + private TestRestTemplate testRestTemplate; + + @SpyBean + private FooComponent fooComponent; + + @Before + public void init() { + Foo foo = new Foo(); + foo.setId(5); + foo.setName("MOCKED_FOO"); + + doReturn(foo).when(fooComponent).getFooWithId(anyInt()); + + // doCallRealMethod().when(fooComponent).getFooWithName(anyString()); + } + + @Test + public void givenInquiryingFooWithId_whenFooComponentIsMocked_thenAssertMockedResult() { + Map pathVariables = new HashMap(); + pathVariables.put("id", "1"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); + + assertNotNull(fooResponse); + assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); + assertEquals(5, fooResponse.getBody().getId().longValue()); + assertEquals("MOCKED_FOO", fooResponse.getBody().getName()); + } + + @Test + public void givenInquiryingFooWithName_whenFooComponentIsMocked_thenAssertMockedResult() { + Map pathVariables = new HashMap(); + pathVariables.put("name", "Foo_Name"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); + + assertNotNull(fooResponse); + assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); + assertEquals(1, fooResponse.getBody().getId().longValue()); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java new file mode 100644 index 0000000000..932cce26d5 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java @@ -0,0 +1,43 @@ +package org.baeldung.boot; +import java.util.HashMap; +import java.util.Map; + +import org.baeldung.boot.DemoApplication; +import org.baeldung.boot.model.Foo; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=DemoApplication.class,webEnvironment = WebEnvironment.RANDOM_PORT) +public class FooIntegrationTest { + + @Autowired + private TestRestTemplate testRestTemplate; + + + @Test + public void givenInquiryingFooWithId_whenIdIsValid_thenHttpStatusOK(){ + Map pathVariables = new HashMap(); + pathVariables.put("id", "1"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); + Assert.assertNotNull(fooResponse); + Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); + } + + @Test + public void givenInquiryingFooWithName_whenNameIsValid_thenHttpStatusOK(){ + Map pathVariables = new HashMap(); + pathVariables.put("name", "Foo_Name"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); + Assert.assertNotNull(fooResponse); + Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java b/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java new file mode 100644 index 0000000000..c29aa64e6c --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java @@ -0,0 +1,34 @@ +package org.baeldung.boot; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.baeldung.boot.model.Foo; +import org.baeldung.boot.repository.FooRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@DataJpaTest +public class FooJPATest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private FooRepository repository; + + @Test + public void findFooByName() { + this.entityManager.persist(new Foo("Foo_Name_2")); + Foo foo = this.repository.findByName("Foo_Name_2"); + assertNotNull(foo); + assertEquals("Foo_Name_2",foo.getName()); + // Due to having Insert query for Foo with Id 1, so TestEntityManager generates new Id of 2 + assertEquals(2l,foo.getId().longValue()); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java b/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java new file mode 100644 index 0000000000..2789ed0a8c --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java @@ -0,0 +1,35 @@ +package org.baeldung.boot; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.baeldung.boot.model.Foo; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@JsonTest +public class FooJsonTest { + + @Autowired + private JacksonTester json; + + + @Test + public void testSerialize() throws Exception { + Foo foo = new Foo(3, "Foo_Name_3"); + assertThat(this.json.write(foo)).isEqualToJson("expected.json"); + assertThat(this.json.write(foo)).hasJsonPathStringValue("@.name"); + assertThat(this.json.write(foo)).extractingJsonPathStringValue("@.name").isEqualTo("Foo_Name_3"); + } + + @Test + public void testDeserialize() throws Exception { + String content = "{\"id\":4,\"name\":\"Foo_Name_4\"}"; + assertThat(this.json.parseObject(content).getName()).isEqualTo("Foo_Name_4"); + assertThat(this.json.parseObject(content).getId()==4); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/resources/application.properties b/spring-boot/src/test/resources/application.properties index 14b190629e..0e6cb86bc5 100644 --- a/spring-boot/src/test/resources/application.properties +++ b/spring-boot/src/test/resources/application.properties @@ -1,3 +1,5 @@ spring.mail.host=localhost spring.mail.port=8025 -spring.mail.properties.mail.smtp.auth=false \ No newline at end of file +spring.mail.properties.mail.smtp.auth=false + +security.basic.enabled=false \ No newline at end of file diff --git a/spring-boot/src/test/resources/import.sql b/spring-boot/src/test/resources/import.sql new file mode 100644 index 0000000000..a382410271 --- /dev/null +++ b/spring-boot/src/test/resources/import.sql @@ -0,0 +1 @@ +Insert into Foo values(1,'Foo_Name'); \ No newline at end of file diff --git a/spring-boot/src/test/resources/org/baeldung/boot/expected.json b/spring-boot/src/test/resources/org/baeldung/boot/expected.json new file mode 100644 index 0000000000..f5409421a6 --- /dev/null +++ b/spring-boot/src/test/resources/org/baeldung/boot/expected.json @@ -0,0 +1,4 @@ +{ + "id":3, + "name":"Foo_Name_3" +} \ No newline at end of file From 656afd6ff53c47a475b5b027a7526c259bcdb569 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 7 Mar 2017 18:51:10 +0100 Subject: [PATCH 060/291] Revert "[BAEL-694] Hibernate immutable annotation (#1302)" (#1327) This reverts commit 6fbf90fd27f0072df1716c7a624b68105ba00287. --- hibernate-immutable/README.md | 2 - hibernate-immutable/pom.xml | 30 ------- .../java/com/baeldung/entities/Event.java | 52 ------------- .../java/com/baeldung/util/HibernateUtil.java | 29 ------- .../src/main/resources/hibernate.cfg.xml | 38 --------- .../src/test/java/EventTest.java | 78 ------------------- 6 files changed, 229 deletions(-) delete mode 100644 hibernate-immutable/README.md delete mode 100644 hibernate-immutable/pom.xml delete mode 100644 hibernate-immutable/src/main/java/com/baeldung/entities/Event.java delete mode 100644 hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java delete mode 100644 hibernate-immutable/src/main/resources/hibernate.cfg.xml delete mode 100644 hibernate-immutable/src/test/java/EventTest.java diff --git a/hibernate-immutable/README.md b/hibernate-immutable/README.md deleted file mode 100644 index f564d8fc3f..0000000000 --- a/hibernate-immutable/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Article -- [Guide to @Immutable Annotation in Hibernate](http://inprogress.baeldung.com/?p=35824&preview=true) diff --git a/hibernate-immutable/pom.xml b/hibernate-immutable/pom.xml deleted file mode 100644 index f4ed2d3cf4..0000000000 --- a/hibernate-immutable/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - 4.0.0 - - com.baeldung - hibernate-immutable - 1.0-SNAPSHOT - - - - org.hibernate - hibernate-core - 4.3.10.Final - - - org.hsqldb - hsqldb - 2.2.9 - - - junit - junit - 4.11 - test - - - - \ No newline at end of file diff --git a/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java b/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java deleted file mode 100644 index a8690a8959..0000000000 --- a/hibernate-immutable/src/main/java/com/baeldung/entities/Event.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.baeldung.entities; - -import org.hibernate.annotations.*; -import org.hibernate.annotations.CascadeType; - -import javax.persistence.*; -import javax.persistence.Entity; -import javax.persistence.Table; -import java.util.Set; - -@Entity -@Immutable -@Table(name = "events") -public class Event { - @Id - @Column(name = "event_id") - @GeneratedValue(generator = "increment") - @GenericGenerator(name = "increment", strategy = "increment") - private Long id; - - @Column(name = "title") - private String title; - - @ElementCollection - @Immutable - private Set guestList; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) - public Set getGuestList() { - return guestList; - } - - public void setGuestList(Set guestList) { - this.guestList = guestList; - } -} diff --git a/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java b/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java deleted file mode 100644 index f802342b86..0000000000 --- a/hibernate-immutable/src/main/java/com/baeldung/util/HibernateUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.baeldung.util; - -import org.hibernate.SessionFactory; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.Configuration; -import org.hibernate.service.ServiceRegistry; - -public class HibernateUtil { - private static final SessionFactory sessionFactory = buildSessionFactory(); - - private static SessionFactory buildSessionFactory() { - try { - // Create a session factory from hibernate.cfg.xml - Configuration configuration = new Configuration(); - configuration.configure("hibernate.cfg.xml"); - ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() - .applySettings(configuration.getProperties()) - .build(); - return configuration.buildSessionFactory(serviceRegistry); - } catch (Throwable ex) { - System.out.println("Initial SessionFactory creation failed." + ex); - throw new ExceptionInInitializerError(ex); - } - } - - public static SessionFactory getSessionFactory() { - return sessionFactory; - } -} diff --git a/hibernate-immutable/src/main/resources/hibernate.cfg.xml b/hibernate-immutable/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index 756191a9e2..0000000000 --- a/hibernate-immutable/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - org.hsqldb.jdbcDriver - jdbc:hsqldb:hsql://localhost/xdb - sa - - - - 1 - - - org.hibernate.dialect.HSQLDialect - - - thread - - - org.hibernate.cache.NoCacheProvider - - - true - - - update - - - - - - \ No newline at end of file diff --git a/hibernate-immutable/src/test/java/EventTest.java b/hibernate-immutable/src/test/java/EventTest.java deleted file mode 100644 index f05aaff5f5..0000000000 --- a/hibernate-immutable/src/test/java/EventTest.java +++ /dev/null @@ -1,78 +0,0 @@ -import com.baeldung.entities.Event; -import com.baeldung.util.HibernateUtil; -import org.hibernate.HibernateException; -import org.hibernate.Session; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import javax.persistence.Table; - -public class EventTest { - - private Session session; - @Rule - public final ExpectedException exception = ExpectedException.none(); - - @Before - public void setup() { - session = HibernateUtil.getSessionFactory().getCurrentSession(); - session.beginTransaction(); - } - - @After - public void teardown() { - HibernateUtil.getSessionFactory().close(); - } - - @Test - public void addEvent() { - Event event = new Event(); - event.setTitle("Public Event"); - session.save(event); - session.getTransaction().commit(); - } - - @Test - public void updateEvent() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='My Event'").list().get(0); - event.setTitle("Public Event"); - session.saveOrUpdate(event); - session.getTransaction().commit(); - } - - @Test - public void deleteEvent() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='My Event'").list().get(0); - session.delete(event); - session.getTransaction().commit(); - } - - @Test - public void addGuest() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='Public Event'").list().get(0); - String newGuest = "Sara"; - event.getGuestList().add(newGuest); - - exception.expect(HibernateException.class); - session.save(event); - session.getTransaction().commit(); - } - - @Test - public void deleteCascade() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='Public Event'").list().get(0); - String guest = event.getGuestList().iterator().next(); - event.getGuestList().remove(guest); - - exception.expect(HibernateException.class); - session.saveOrUpdate(event); - session.getTransaction().commit(); - } -} From 250cb7c16449a64c0b407bef83e749914be2d858 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 7 Mar 2017 19:21:40 +0100 Subject: [PATCH 061/291] Refactor Spring-boot-test examples (#1328) * Refactor Spring-boot-test examples * Refactor Spring-boot-test examples --- .../boot/components/FooComponent.java | 43 ++----------------- .../org/baeldung/boot/service/FooService.java | 32 +++----------- .../org/baeldung/boot/FooComponentTests.java | 26 +++++------ 3 files changed, 24 insertions(+), 77 deletions(-) diff --git a/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java b/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java index b327958c16..d666b11c8c 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java +++ b/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java @@ -1,58 +1,21 @@ package org.baeldung.boot.components; -import org.baeldung.boot.exceptions.CommonException; -import org.baeldung.boot.exceptions.FooNotFoundException; import org.baeldung.boot.model.Foo; import org.baeldung.boot.repository.FooRepository; -import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.google.common.base.Preconditions; - @Component public class FooComponent { @Autowired private FooRepository fooRepository; - private final static Logger logger = org.slf4j.LoggerFactory.getLogger(FooComponent.class); - - public Foo getFooWithId(Integer id) { - - Foo foo = null; - - try { - foo = fooRepository.findOne(id); - Preconditions.checkNotNull(foo); - logger.info("Foo with Id {} found",id); - }catch(NullPointerException ex){ - logger.error("Foo with Id {} was not found",id); - throw new FooNotFoundException("The given foo Id was not found"); - } catch (Exception ex) { - logger.error("Error while retrieving Foo with Id {} found",id,ex); - throw new CommonException("Error while retrieving foo"); - } - - return foo; + public Foo getFooWithId(Integer id) throws Exception { + return fooRepository.findOne(id); } public Foo getFooWithName(String name) { - - Foo foo = null; - - try { - foo = fooRepository.findByName(name); - Preconditions.checkNotNull(foo); - logger.info("Foo with name {} found",name); - }catch(NullPointerException ex){ - logger.error("Foo with name {} was not found",name); - throw new FooNotFoundException("The given foo name was not found"); - } catch (Exception ex) { - logger.error("Error while retrieving Foo with name {} found",name,ex); - throw new CommonException("Error while retrieving foo"); - } - - return foo; + return fooRepository.findByName(name); } } \ No newline at end of file diff --git a/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java b/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java index 2cb64ea139..6f19a1974c 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java +++ b/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java @@ -1,19 +1,13 @@ package org.baeldung.boot.service; import org.baeldung.boot.components.FooComponent; -import org.baeldung.boot.exceptions.CommonException; -import org.baeldung.boot.exceptions.FooNotFoundException; import org.baeldung.boot.model.Foo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @RestController @@ -22,31 +16,19 @@ public class FooService { @Autowired private FooComponent fooComponent; - @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getFooWithId(@PathVariable Integer id) { + @GetMapping("/{id}") + public ResponseEntity getFooWithId(@PathVariable Integer id) throws Exception { Foo foo = fooComponent.getFooWithId(id); - return new ResponseEntity(foo, HttpStatus.OK); + return new ResponseEntity<>(foo, HttpStatus.OK); } - @RequestMapping(value = "/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getFooWithName(@RequestParam String name) { + @GetMapping("/") + public ResponseEntity getFooWithName(@RequestParam String name) throws Exception { Foo foo = fooComponent.getFooWithName(name); - return new ResponseEntity(foo, HttpStatus.OK); - } - - @ExceptionHandler(value = FooNotFoundException.class) - @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Foo not found") - public void handleFooNotFoundException() { - - } - - @ExceptionHandler(value = CommonException.class) - @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Common exception") - public void handleCommonException() { - + return new ResponseEntity<>(foo, HttpStatus.OK); } } \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java index 775f7c1ef0..0a5de7dc7a 100644 --- a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java +++ b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java @@ -1,13 +1,5 @@ package org.baeldung.boot; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.doReturn; - -import java.util.HashMap; -import java.util.Map; - import org.baeldung.boot.components.FooComponent; import org.baeldung.boot.model.Foo; import org.junit.Before; @@ -22,8 +14,18 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; + @RunWith(SpringRunner.class) -@SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@SpringBootTest( + classes = DemoApplication.class, + webEnvironment = WebEnvironment.RANDOM_PORT) public class FooComponentTests { @Autowired @@ -33,7 +35,7 @@ public class FooComponentTests { private FooComponent fooComponent; @Before - public void init() { + public void init() throws Exception { Foo foo = new Foo(); foo.setId(5); foo.setName("MOCKED_FOO"); @@ -45,7 +47,7 @@ public class FooComponentTests { @Test public void givenInquiryingFooWithId_whenFooComponentIsMocked_thenAssertMockedResult() { - Map pathVariables = new HashMap(); + Map pathVariables = new HashMap<>(); pathVariables.put("id", "1"); ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); @@ -57,7 +59,7 @@ public class FooComponentTests { @Test public void givenInquiryingFooWithName_whenFooComponentIsMocked_thenAssertMockedResult() { - Map pathVariables = new HashMap(); + Map pathVariables = new HashMap<>(); pathVariables.put("name", "Foo_Name"); ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); From 62db91ef1ffba80834473c0debce4365f68d0702 Mon Sep 17 00:00:00 2001 From: Alex Vargas Date: Tue, 7 Mar 2017 13:11:49 -0800 Subject: [PATCH 062/291] Bael 389 - Building URL dynamically between host and pathname (#1323) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces * BAEL-389 - Building URL dynamically between host and pathname --- java-websocket/src/main/webapp/websocket.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/java-websocket/src/main/webapp/websocket.js b/java-websocket/src/main/webapp/websocket.js index 39e5687f0c..c23b2722fe 100644 --- a/java-websocket/src/main/webapp/websocket.js +++ b/java-websocket/src/main/webapp/websocket.js @@ -2,8 +2,11 @@ var ws; function connect() { var username = document.getElementById("username").value; - ws = new WebSocket("ws://" + document.location.host + "/java-websocket/chat/" + username); - + + var host = document.location.host; + var pathname = document.location.pathname; + + ws = new WebSocket("ws://" +host + pathname + "chat/" + username); ws.onmessage = function(event) { var log = document.getElementById("log"); From fde269c51e5a32280d3be37a4420ddd89746cde1 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Wed, 8 Mar 2017 06:13:17 +0100 Subject: [PATCH 063/291] Rename classes (#1331) --- .../components/{FooComponent.java => FooService.java} | 2 +- .../service/{FooService.java => FooController.java} | 10 +++++----- .../test/java/org/baeldung/boot/FooComponentTests.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename spring-boot/src/main/java/org/baeldung/boot/components/{FooComponent.java => FooService.java} (94%) rename spring-boot/src/main/java/org/baeldung/boot/service/{FooService.java => FooController.java} (79%) diff --git a/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java b/spring-boot/src/main/java/org/baeldung/boot/components/FooService.java similarity index 94% rename from spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java rename to spring-boot/src/main/java/org/baeldung/boot/components/FooService.java index d666b11c8c..235fd43299 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/components/FooComponent.java +++ b/spring-boot/src/main/java/org/baeldung/boot/components/FooService.java @@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class FooComponent { +public class FooService { @Autowired private FooRepository fooRepository; diff --git a/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java b/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java similarity index 79% rename from spring-boot/src/main/java/org/baeldung/boot/service/FooService.java rename to spring-boot/src/main/java/org/baeldung/boot/service/FooController.java index 6f19a1974c..abd3fccba1 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/service/FooService.java +++ b/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java @@ -1,6 +1,6 @@ package org.baeldung.boot.service; -import org.baeldung.boot.components.FooComponent; +import org.baeldung.boot.components.FooService; import org.baeldung.boot.model.Foo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -11,15 +11,15 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController -public class FooService { +public class FooController { @Autowired - private FooComponent fooComponent; + private FooService fooService; @GetMapping("/{id}") public ResponseEntity getFooWithId(@PathVariable Integer id) throws Exception { - Foo foo = fooComponent.getFooWithId(id); + Foo foo = fooService.getFooWithId(id); return new ResponseEntity<>(foo, HttpStatus.OK); } @@ -27,7 +27,7 @@ public class FooService { @GetMapping("/") public ResponseEntity getFooWithName(@RequestParam String name) throws Exception { - Foo foo = fooComponent.getFooWithName(name); + Foo foo = fooService.getFooWithName(name); return new ResponseEntity<>(foo, HttpStatus.OK); } diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java index 0a5de7dc7a..72ccc0bfb8 100644 --- a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java +++ b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java @@ -1,6 +1,6 @@ package org.baeldung.boot; -import org.baeldung.boot.components.FooComponent; +import org.baeldung.boot.components.FooService; import org.baeldung.boot.model.Foo; import org.junit.Before; import org.junit.Test; @@ -32,7 +32,7 @@ public class FooComponentTests { private TestRestTemplate testRestTemplate; @SpyBean - private FooComponent fooComponent; + private FooService fooService; @Before public void init() throws Exception { @@ -40,7 +40,7 @@ public class FooComponentTests { foo.setId(5); foo.setName("MOCKED_FOO"); - doReturn(foo).when(fooComponent).getFooWithId(anyInt()); + doReturn(foo).when(fooService).getFooWithId(anyInt()); // doCallRealMethod().when(fooComponent).getFooWithName(anyString()); } From a41923722671700668001e1afd1fe78582aafd88 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Wed, 8 Mar 2017 10:45:51 +0100 Subject: [PATCH 064/291] BAEL-550 Axon framework * BEEL-550 create axon module * BEEL-550 proper naming * BEEL-550 better example of message service * BEEL-550 proper name of method * BEEL-550 remove not needed comments * BEEL-550 proper message * BEEL-550 axon test scope test * BEEL-550 tries to migrate to axon 3 * BEEL-550 migrate to vesrion 3 successfull --- axon/pom.xml | 52 ++++++++++++++++++ .../com/baeldung/axon/MessagesRunner.java | 54 +++++++++++++++++++ .../axon/aggregates/MessagesAggregate.java | 36 +++++++++++++ .../axon/commands/CreateMessageCommand.java | 24 +++++++++ .../axon/commands/MarkReadMessageCommand.java | 18 +++++++ .../eventhandlers/MessagesEventHandler.java | 19 +++++++ .../axon/events/MessageCreatedEvent.java | 20 +++++++ .../axon/events/MessageReadEvent.java | 14 +++++ .../baeldung/axon/MessagesAggregateTest.java | 42 +++++++++++++++ pom.xml | 1 + 10 files changed, 280 insertions(+) create mode 100644 axon/pom.xml create mode 100644 axon/src/main/java/com/baeldung/axon/MessagesRunner.java create mode 100644 axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java create mode 100644 axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java create mode 100644 axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java create mode 100644 axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java create mode 100644 axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java create mode 100644 axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java diff --git a/axon/pom.xml b/axon/pom.xml new file mode 100644 index 0000000000..2bffa53bb8 --- /dev/null +++ b/axon/pom.xml @@ -0,0 +1,52 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + axon + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + + org.axonframework + axon-test + ${axon.version} + test + + + org.axonframework + axon-core + ${axon.version} + + + junit + junit + ${junit.version} + test + + + + + 3.0.2 + 4.12 + + + + \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java new file mode 100644 index 0000000000..77b50d09bd --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java @@ -0,0 +1,54 @@ +package com.baeldung.axon; + +import com.baeldung.axon.aggregates.MessagesAggregate; +import com.baeldung.axon.commands.CreateMessageCommand; +import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.eventhandlers.MessagesEventHandler; +import org.axonframework.commandhandling.AggregateAnnotationCommandHandler; +import org.axonframework.commandhandling.CommandBus; +import org.axonframework.commandhandling.SimpleCommandBus; +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.axonframework.commandhandling.gateway.DefaultCommandGateway; +import org.axonframework.eventhandling.AnnotationEventListenerAdapter; +import org.axonframework.eventsourcing.EventSourcingRepository; +import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore; +import org.axonframework.eventsourcing.eventstore.EventStore; +import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine; + +import java.util.UUID; + +public class MessagesRunner { + + public static void main(String[] args) { + CommandBus commandBus = new SimpleCommandBus(); + + CommandGateway commandGateway = new DefaultCommandGateway(commandBus); + + EventStore eventStore = new EmbeddedEventStore(new InMemoryEventStorageEngine()); + + EventSourcingRepository repository = + new EventSourcingRepository<>(MessagesAggregate.class, eventStore); + + + AggregateAnnotationCommandHandler messagesAggregateAggregateAnnotationCommandHandler = + new AggregateAnnotationCommandHandler(MessagesAggregate.class, repository); + messagesAggregateAggregateAnnotationCommandHandler.subscribe(commandBus); + + final AnnotationEventListenerAdapter annotationEventListenerAdapter = + new AnnotationEventListenerAdapter(new MessagesEventHandler()); + eventStore.subscribe(eventMessages -> eventMessages.forEach(e -> { + try { + annotationEventListenerAdapter.handle(e); + } catch (Exception e1) { + throw new RuntimeException(e1); + + } + } + + )); + + final String itemId = UUID.randomUUID().toString(); + commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)")); + commandGateway.send(new MarkReadMessageCommand(itemId)); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java new file mode 100644 index 0000000000..e762604b74 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java @@ -0,0 +1,36 @@ +package com.baeldung.axon.aggregates; + +import com.baeldung.axon.commands.CreateMessageCommand; +import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.events.MessageCreatedEvent; +import com.baeldung.axon.events.MessageReadEvent; +import org.axonframework.commandhandling.CommandHandler; +import org.axonframework.commandhandling.model.AggregateIdentifier; +import org.axonframework.eventhandling.EventHandler; + +import static org.axonframework.commandhandling.model.AggregateLifecycle.apply; + + +public class MessagesAggregate { + + @AggregateIdentifier + private String id; + + public MessagesAggregate() { + } + + @CommandHandler + public MessagesAggregate(CreateMessageCommand command) { + apply(new MessageCreatedEvent(command.getId(), command.getText())); + } + + @EventHandler + public void on(MessageCreatedEvent event) { + this.id = event.getId(); + } + + @CommandHandler + public void markRead(MarkReadMessageCommand command) { + apply(new MessageReadEvent(id)); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java new file mode 100644 index 0000000000..d0651bf12e --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java @@ -0,0 +1,24 @@ +package com.baeldung.axon.commands; + + +import org.axonframework.commandhandling.TargetAggregateIdentifier; + +public class CreateMessageCommand { + + @TargetAggregateIdentifier + private final String id; + private final String text; + + public CreateMessageCommand(String id, String text) { + this.id = id; + this.text = text; + } + + public String getId() { + return id; + } + + public String getText() { + return text; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java new file mode 100644 index 0000000000..e66582d9ec --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java @@ -0,0 +1,18 @@ +package com.baeldung.axon.commands; + + +import org.axonframework.commandhandling.TargetAggregateIdentifier; + +public class MarkReadMessageCommand { + + @TargetAggregateIdentifier + private final String id; + + public MarkReadMessageCommand(String id) { + this.id = id; + } + + public String getId() { + return id; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java new file mode 100644 index 0000000000..3e51e19c4e --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java @@ -0,0 +1,19 @@ +package com.baeldung.axon.eventhandlers; + +import com.baeldung.axon.events.MessageReadEvent; +import com.baeldung.axon.events.MessageCreatedEvent; +import org.axonframework.eventhandling.EventHandler; + + +public class MessagesEventHandler { + + @EventHandler + public void handle(MessageCreatedEvent event) { + System.out.println("Message received: " + event.getText() + " (" + event.getId() + ")"); + } + + @EventHandler + public void handle(MessageReadEvent event) { + System.out.println("Message read: " + event.getId()); + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java new file mode 100644 index 0000000000..3c9aac5ed8 --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java @@ -0,0 +1,20 @@ +package com.baeldung.axon.events; + +public class MessageCreatedEvent { + + private final String id; + private final String text; + + public MessageCreatedEvent(String id, String text) { + this.id = id; + this.text = text; + } + + public String getId() { + return id; + } + + public String getText() { + return text; + } +} \ No newline at end of file diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java new file mode 100644 index 0000000000..57bfc8e19e --- /dev/null +++ b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java @@ -0,0 +1,14 @@ +package com.baeldung.axon.events; + +public class MessageReadEvent { + + private final String id; + + public MessageReadEvent(String id) { + this.id = id; + } + + public String getId() { + return id; + } +} \ No newline at end of file diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java new file mode 100644 index 0000000000..bbeff18f27 --- /dev/null +++ b/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java @@ -0,0 +1,42 @@ +package com.baeldung.axon; + +import com.baeldung.axon.aggregates.MessagesAggregate; +import com.baeldung.axon.commands.CreateMessageCommand; +import com.baeldung.axon.commands.MarkReadMessageCommand; +import com.baeldung.axon.events.MessageCreatedEvent; +import com.baeldung.axon.events.MessageReadEvent; +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.Before; +import org.junit.Test; + +import java.util.UUID; + +public class MessagesAggregateTest { + + private FixtureConfiguration fixture; + + @Before + public void setUp() throws Exception { + fixture = new AggregateTestFixture(MessagesAggregate.class); + + } + + @Test + public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() throws Exception { + String eventText = "Hello, how is your day?"; + String id = UUID.randomUUID().toString(); + fixture.given() + .when(new CreateMessageCommand(id, eventText)) + .expectEvents(new MessageCreatedEvent(id, eventText)); + } + + @Test + public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() throws Exception { + String id = UUID.randomUUID().toString(); + + fixture.given(new MessageCreatedEvent(id, "Hello :-)")) + .when(new MarkReadMessageCommand(id)) + .expectEvents(new MessageReadEvent(id)); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9243770060..ce66ff4159 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ aspectj assertj autovalue + axon cdi From 9758e2ce3ce77313d113be02d704b29ac1d9730b Mon Sep 17 00:00:00 2001 From: pivovarit Date: Wed, 8 Mar 2017 14:23:56 +0100 Subject: [PATCH 065/291] ACO refactor --- .../ga/ant_colony/AntColonyOptimization.java | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java index 27a270f906..09c2c109f6 100644 --- a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java +++ b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java @@ -18,8 +18,8 @@ public class AntColonyOptimization { private int maxIterations = 1000; - public int numberOfCities; - public int numberOfAnts; + private int numberOfCities; + private int numberOfAnts; private double graph[][]; private double trails[][]; private List ants = new ArrayList<>(); @@ -28,8 +28,8 @@ public class AntColonyOptimization { private int currentIndex; - public int[] bestTourOrder; - public double bestTourLength; + private int[] bestTourOrder; + private double bestTourLength; public AntColonyOptimization(int noOfCities) { graph = generateRandomMatrix(noOfCities); @@ -43,26 +43,17 @@ public class AntColonyOptimization { /** * Generate initial solution - * - * @param n - * @return */ public double[][] generateRandomMatrix(int n) { double[][] randomMatrix = new double[n][n]; - random.setSeed(System.currentTimeMillis()); - IntStream.range(0, n).forEach(i -> { - IntStream.range(0, n).forEach(j -> { - Integer r = random.nextInt(100) + 1; - randomMatrix[i][j] = Math.abs(r); - }); - }); + IntStream.range(0, n) + .forEach(i -> IntStream.range(0, n) + .forEach(j -> randomMatrix[i][j] = Math.abs(random.nextInt(100) + 1))); return randomMatrix; } /** * Perform ant optimization - * - * @return */ public void startAntOptimization() { IntStream.rangeClosed(1, 3).forEach(i -> { @@ -73,8 +64,6 @@ public class AntColonyOptimization { /** * Use this method to run the main logic - * - * @return */ public int[] solve() { setupAnts(); @@ -94,7 +83,7 @@ public class AntColonyOptimization { */ private void setupAnts() { IntStream.range(0, numberOfAnts).forEach(i -> { - ants.stream().forEach(ant -> { + ants.forEach(ant -> { ant.clear(); ant.visitCity(-1, random.nextInt(numberOfCities)); }); @@ -107,23 +96,18 @@ public class AntColonyOptimization { */ private void moveAnts() { IntStream.range(currentIndex, numberOfCities - 1).forEach(i -> { - ants.stream().forEach(ant -> { - ant.visitCity(currentIndex, selectNextCity(ant)); - }); + ants.forEach(ant -> ant.visitCity(currentIndex, selectNextCity(ant))); currentIndex++; }); } /** * Select next city for each ant - * - * @param ant - * @return */ private int selectNextCity(Ant ant) { int t = random.nextInt(numberOfCities - currentIndex); if (random.nextDouble() < randomFactor) { - IntStream.range(0, numberOfCities).filter(i -> i == t && !ant.visited(i)).findFirst(); + IntStream.range(0, numberOfCities).filter(i -> i == t && !ant.visited(i)).findFirst(); //TODO unused } calculateProbabilities(ant); double r = random.nextDouble(); @@ -140,8 +124,6 @@ public class AntColonyOptimization { /** * Calculate the next city picks probabilites - * - * @param ant */ public void calculateProbabilities(Ant ant) { int i = ant.trail[currentIndex]; From 18710230ab7b1fe731e13b21a3ec266d9a7fb572 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 8 Mar 2017 09:35:27 -0600 Subject: [PATCH 066/291] BAEL-157: README.md updated (#1338) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated --- spring-data-rest/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-data-rest/README.md b/spring-data-rest/README.md index f77c4dc202..241f2e3bcf 100644 --- a/spring-data-rest/README.md +++ b/spring-data-rest/README.md @@ -16,3 +16,4 @@ To view the running application, visit [http://localhost:8080](http://localhost: ###Relevant Articles: - [Guide to Spring Data REST Validators](http://www.baeldung.com/spring-data-rest-validators) - [Working with Relationships in Spring Data REST](http://www.baeldung.com/spring-data-rest-relationships) +- [AngularJS CRUD Application with Spring Data REST](http://www.baeldung.com/angularjs-crud-with-spring-data-rest) From 3abb98e9e8acc7efe3f9f8423fcf0f8934655be7 Mon Sep 17 00:00:00 2001 From: maibin Date: Thu, 9 Mar 2017 04:21:47 +0100 Subject: [PATCH 067/291] Final fixes on ACO (#1339) * Ant Colony Optimization * Updated code for Ant Colony --- algorithms/pom.xml | 7 + .../com/baeldung/algorithms/RunAlgorithm.java | 6 +- .../algorithms/ga/annealing/City.java | 0 .../ga/annealing/SimulatedAnnealing.java | 0 .../algorithms/ga/annealing/Travel.java | 0 .../algorithms/ga/ant_colony/Ant.java | 0 .../ga/ant_colony/AntColonyOptimization.java | 203 ++++++++++++++++++ .../algorithms/ga/binary/Individual.java | 0 .../algorithms/ga/binary/Population.java | 0 .../ga/binary/SimpleGeneticAlgorithm.java | 0 .../{ => ga}/dijkstra/Dijkstra.java | 2 +- .../algorithms/{ => ga}/dijkstra/Graph.java | 2 +- .../algorithms/{ => ga}/dijkstra/Node.java | 2 +- .../algorithms/slope_one/InputData.java | 0 .../baeldung/algorithms/slope_one/Item.java | 0 .../algorithms/slope_one/SlopeOne.java | 0 .../baeldung/algorithms/slope_one/User.java | 0 .../algorithms/AntColonyOptimizationTest.java | 2 +- .../BinaryGeneticAlgorithmUnitTest.java | 2 +- .../algorithms/DijkstraAlgorithmTest.java | 7 +- .../algorithms/SimulatedAnnealingTest.java | 2 +- .../ga/ant_colony/AntColonyOptimization.java | 189 ---------------- .../PrimitiveConversionsJUnitTest.java | 2 +- 23 files changed, 226 insertions(+), 200 deletions(-) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/RunAlgorithm.java (84%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/annealing/City.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java (100%) create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/binary/Individual.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/binary/Population.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/ga/binary/SimpleGeneticAlgorithm.java (100%) rename algorithms/src/main/java/com/baeldung/algorithms/{ => ga}/dijkstra/Dijkstra.java (95%) rename algorithms/src/main/java/com/baeldung/algorithms/{ => ga}/dijkstra/Graph.java (83%) rename algorithms/src/main/java/com/baeldung/algorithms/{ => ga}/dijkstra/Node.java (92%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/slope_one/InputData.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/slope_one/Item.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/slope_one/SlopeOne.java (100%) rename {core-java => algorithms}/src/main/java/com/baeldung/algorithms/slope_one/User.java (100%) rename {core-java/src/test/java/com/baeldung => algorithms/src/test/java}/algorithms/AntColonyOptimizationTest.java (93%) rename {core-java/src/test/java/com/baeldung => algorithms/src/test/java}/algorithms/BinaryGeneticAlgorithmUnitTest.java (91%) rename {core-java/src/test/java/com/baeldung => algorithms/src/test/java}/algorithms/SimulatedAnnealingTest.java (90%) delete mode 100644 core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java diff --git a/algorithms/pom.xml b/algorithms/pom.xml index f72457650a..46a2b9d897 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -9,6 +9,7 @@ 4.12 3.6.0 1.5.0 + 1.16.12 @@ -18,6 +19,12 @@ ${junit.version} test + + org.projectlombok + lombok + ${lombok.version} + provided + diff --git a/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/RunAlgorithm.java similarity index 84% rename from core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java rename to algorithms/src/main/java/com/baeldung/algorithms/RunAlgorithm.java index 22c5776293..6ab7dbb4e5 100644 --- a/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/RunAlgorithm.java @@ -9,13 +9,14 @@ import com.baeldung.algorithms.slope_one.SlopeOne; public class RunAlgorithm { - public static void main(String[] args) { + public static void main(String[] args) throws InstantiationException, IllegalAccessException { Scanner in = new Scanner(System.in); System.out.println("Run algorithm:"); System.out.println("1 - Simulated Annealing"); System.out.println("2 - Slope One"); System.out.println("3 - Simple Genetic Algorithm"); System.out.println("4 - Ant Colony"); + System.out.println("5 - Dijkstra"); int decision = in.nextInt(); switch (decision) { case 1: @@ -33,6 +34,9 @@ public class RunAlgorithm { AntColonyOptimization antColony = new AntColonyOptimization(21); antColony.startAntOptimization(); break; + case 5: + System.out.println("Please run the DijkstraAlgorithmTest."); + break; default: System.out.println("Unknown option"); break; diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/City.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/City.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/annealing/City.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/City.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java new file mode 100644 index 0000000000..62e124d3f3 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java @@ -0,0 +1,203 @@ +package com.baeldung.algorithms.ga.ant_colony; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.OptionalInt; +import java.util.Random; +import java.util.stream.IntStream; + +public class AntColonyOptimization { + + private double c = 1.0; + private double alpha = 1; + private double beta = 5; + private double evaporation = 0.5; + private double Q = 500; + private double antFactor = 0.8; + private double randomFactor = 0.01; + + private int maxIterations = 1000; + + private int numberOfCities; + private int numberOfAnts; + private double graph[][]; + private double trails[][]; + private List ants = new ArrayList<>(); + private Random random = new Random(); + private double probabilities[]; + + private int currentIndex; + + private int[] bestTourOrder; + private double bestTourLength; + + public AntColonyOptimization(int noOfCities) { + graph = generateRandomMatrix(noOfCities); + numberOfCities = graph.length; + numberOfAnts = (int) (numberOfCities * antFactor); + + trails = new double[numberOfCities][numberOfCities]; + probabilities = new double[numberOfCities]; + IntStream.range(0, numberOfAnts) + .forEach(i -> ants.add(new Ant(numberOfCities))); + } + + /** + * Generate initial solution + */ + public double[][] generateRandomMatrix(int n) { + double[][] randomMatrix = new double[n][n]; + IntStream.range(0, n) + .forEach(i -> IntStream.range(0, n) + .forEach(j -> randomMatrix[i][j] = Math.abs(random.nextInt(100) + 1))); + return randomMatrix; + } + + /** + * Perform ant optimization + */ + public void startAntOptimization() { + IntStream.rangeClosed(1, 3) + .forEach(i -> { + System.out.println("Attempt #" + i); + solve(); + }); + } + + /** + * Use this method to run the main logic + */ + public int[] solve() { + setupAnts(); + clearTrails(); + IntStream.range(0, maxIterations) + .forEach(i -> { + moveAnts(); + updateTrails(); + updateBest(); + }); + System.out.println("Best tour length: " + (bestTourLength - numberOfCities)); + System.out.println("Best tour order: " + Arrays.toString(bestTourOrder)); + return bestTourOrder.clone(); + } + + /** + * Prepare ants for the simulation + */ + private void setupAnts() { + IntStream.range(0, numberOfAnts) + .forEach(i -> { + ants.forEach(ant -> { + ant.clear(); + ant.visitCity(-1, random.nextInt(numberOfCities)); + }); + }); + currentIndex = 0; + } + + /** + * At each iteration, move ants + */ + private void moveAnts() { + IntStream.range(currentIndex, numberOfCities - 1) + .forEach(i -> { + ants.forEach(ant -> ant.visitCity(currentIndex, selectNextCity(ant))); + currentIndex++; + }); + } + + /** + * Select next city for each ant + */ + private int selectNextCity(Ant ant) { + int t = random.nextInt(numberOfCities - currentIndex); + if (random.nextDouble() < randomFactor) { + OptionalInt cityIndex = IntStream.range(0, numberOfCities) + .filter(i -> i == t && !ant.visited(i)) + .findFirst(); + if (cityIndex.isPresent()) { + return cityIndex.getAsInt(); + } + } + calculateProbabilities(ant); + double r = random.nextDouble(); + double total = 0; + for (int i = 0; i < numberOfCities; i++) { + total += probabilities[i]; + if (total >= r) { + return i; + } + } + + throw new RuntimeException("There are no other cities"); + } + + /** + * Calculate the next city picks probabilites + */ + public void calculateProbabilities(Ant ant) { + int i = ant.trail[currentIndex]; + double pheromone = 0.0; + for (int l = 0; l < numberOfCities; l++) { + if (!ant.visited(l)) { + pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta); + } + } + for (int j = 0; j < numberOfCities; j++) { + if (ant.visited(j)) { + probabilities[j] = 0.0; + } else { + double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta); + probabilities[j] = numerator / pheromone; + } + } + } + + /** + * Update trails that ants used + */ + private void updateTrails() { + for (int i = 0; i < numberOfCities; i++) { + for (int j = 0; j < numberOfCities; j++) { + trails[i][j] *= evaporation; + } + } + for (Ant a : ants) { + double contribution = Q / a.trailLength(graph); + for (int i = 0; i < numberOfCities - 1; i++) { + trails[a.trail[i]][a.trail[i + 1]] += contribution; + } + trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution; + } + } + + /** + * Update the best solution + */ + private void updateBest() { + if (bestTourOrder == null) { + bestTourOrder = ants.get(0).trail; + bestTourLength = ants.get(0) + .trailLength(graph); + } + for (Ant a : ants) { + if (a.trailLength(graph) < bestTourLength) { + bestTourLength = a.trailLength(graph); + bestTourOrder = a.trail.clone(); + } + } + } + + /** + * Clear trails after simulation + */ + private void clearTrails() { + IntStream.range(0, numberOfCities) + .forEach(i -> { + IntStream.range(0, numberOfCities) + .forEach(j -> trails[i][j] = c); + }); + } + +} diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/binary/Individual.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/binary/Individual.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/binary/Individual.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/binary/Individual.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/binary/Population.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/binary/Population.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/binary/Population.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/binary/Population.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/binary/SimpleGeneticAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/binary/SimpleGeneticAlgorithm.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/ga/binary/SimpleGeneticAlgorithm.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/binary/SimpleGeneticAlgorithm.java diff --git a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Dijkstra.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java similarity index 95% rename from algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Dijkstra.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java index 1d41f46adb..046f13983d 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Dijkstra.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms.dijkstra; +package com.baeldung.algorithms.ga.dijkstra; import java.util.HashSet; import java.util.LinkedList; diff --git a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Graph.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java similarity index 83% rename from algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Graph.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java index f24d6ae60e..00db4b01e4 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Graph.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms.dijkstra; +package com.baeldung.algorithms.ga.dijkstra; import java.util.HashSet; import java.util.Set; diff --git a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Node.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java similarity index 92% rename from algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Node.java rename to algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java index b00127a259..256f12e204 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/dijkstra/Node.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms.dijkstra; +package com.baeldung.algorithms.ga.dijkstra; import java.util.HashMap; import java.util.LinkedList; diff --git a/core-java/src/main/java/com/baeldung/algorithms/slope_one/InputData.java b/algorithms/src/main/java/com/baeldung/algorithms/slope_one/InputData.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/slope_one/InputData.java rename to algorithms/src/main/java/com/baeldung/algorithms/slope_one/InputData.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/slope_one/Item.java b/algorithms/src/main/java/com/baeldung/algorithms/slope_one/Item.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/slope_one/Item.java rename to algorithms/src/main/java/com/baeldung/algorithms/slope_one/Item.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/slope_one/SlopeOne.java b/algorithms/src/main/java/com/baeldung/algorithms/slope_one/SlopeOne.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/slope_one/SlopeOne.java rename to algorithms/src/main/java/com/baeldung/algorithms/slope_one/SlopeOne.java diff --git a/core-java/src/main/java/com/baeldung/algorithms/slope_one/User.java b/algorithms/src/main/java/com/baeldung/algorithms/slope_one/User.java similarity index 100% rename from core-java/src/main/java/com/baeldung/algorithms/slope_one/User.java rename to algorithms/src/main/java/com/baeldung/algorithms/slope_one/User.java diff --git a/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java b/algorithms/src/test/java/algorithms/AntColonyOptimizationTest.java similarity index 93% rename from core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java rename to algorithms/src/test/java/algorithms/AntColonyOptimizationTest.java index 40d2464ab6..a11f5db698 100644 --- a/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java +++ b/algorithms/src/test/java/algorithms/AntColonyOptimizationTest.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms; +package algorithms; import org.junit.Assert; import org.junit.Test; diff --git a/core-java/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmUnitTest.java b/algorithms/src/test/java/algorithms/BinaryGeneticAlgorithmUnitTest.java similarity index 91% rename from core-java/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmUnitTest.java rename to algorithms/src/test/java/algorithms/BinaryGeneticAlgorithmUnitTest.java index 2e92177c8c..2ba516d310 100644 --- a/core-java/src/test/java/com/baeldung/algorithms/BinaryGeneticAlgorithmUnitTest.java +++ b/algorithms/src/test/java/algorithms/BinaryGeneticAlgorithmUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms; +package algorithms; import org.junit.Assert; import org.junit.Test; diff --git a/algorithms/src/test/java/algorithms/DijkstraAlgorithmTest.java b/algorithms/src/test/java/algorithms/DijkstraAlgorithmTest.java index 07606bde4b..4d8cebed25 100644 --- a/algorithms/src/test/java/algorithms/DijkstraAlgorithmTest.java +++ b/algorithms/src/test/java/algorithms/DijkstraAlgorithmTest.java @@ -1,10 +1,11 @@ package algorithms; -import com.baeldung.algorithms.dijkstra.Dijkstra; -import com.baeldung.algorithms.dijkstra.Graph; -import com.baeldung.algorithms.dijkstra.Node; import org.junit.Test; +import com.baeldung.algorithms.ga.dijkstra.Dijkstra; +import com.baeldung.algorithms.ga.dijkstra.Graph; +import com.baeldung.algorithms.ga.dijkstra.Node; + import java.util.Arrays; import java.util.List; diff --git a/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java b/algorithms/src/test/java/algorithms/SimulatedAnnealingTest.java similarity index 90% rename from core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java rename to algorithms/src/test/java/algorithms/SimulatedAnnealingTest.java index 6822bae990..f716b9ffb4 100644 --- a/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java +++ b/algorithms/src/test/java/algorithms/SimulatedAnnealingTest.java @@ -1,4 +1,4 @@ -package com.baeldung.algorithms; +package algorithms; import org.junit.Assert; import org.junit.Test; diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java deleted file mode 100644 index 09c2c109f6..0000000000 --- a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.baeldung.algorithms.ga.ant_colony; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.stream.IntStream; - -public class AntColonyOptimization { - - private double c = 1.0; - private double alpha = 1; - private double beta = 5; - private double evaporation = 0.5; - private double Q = 500; - private double antFactor = 0.8; - private double randomFactor = 0.01; - - private int maxIterations = 1000; - - private int numberOfCities; - private int numberOfAnts; - private double graph[][]; - private double trails[][]; - private List ants = new ArrayList<>(); - private Random random = new Random(); - private double probabilities[]; - - private int currentIndex; - - private int[] bestTourOrder; - private double bestTourLength; - - public AntColonyOptimization(int noOfCities) { - graph = generateRandomMatrix(noOfCities); - numberOfCities = graph.length; - numberOfAnts = (int) (numberOfCities * antFactor); - - trails = new double[numberOfCities][numberOfCities]; - probabilities = new double[numberOfCities]; - IntStream.range(0, numberOfAnts).forEach(i -> ants.add(new Ant(numberOfCities))); - } - - /** - * Generate initial solution - */ - public double[][] generateRandomMatrix(int n) { - double[][] randomMatrix = new double[n][n]; - IntStream.range(0, n) - .forEach(i -> IntStream.range(0, n) - .forEach(j -> randomMatrix[i][j] = Math.abs(random.nextInt(100) + 1))); - return randomMatrix; - } - - /** - * Perform ant optimization - */ - public void startAntOptimization() { - IntStream.rangeClosed(1, 3).forEach(i -> { - System.out.println("Attempt #" + i); - solve(); - }); - } - - /** - * Use this method to run the main logic - */ - public int[] solve() { - setupAnts(); - clearTrails(); - IntStream.range(0, maxIterations).forEach(i -> { - moveAnts(); - updateTrails(); - updateBest(); - }); - System.out.println("Best tour length: " + (bestTourLength - numberOfCities)); - System.out.println("Best tour order: " + Arrays.toString(bestTourOrder)); - return bestTourOrder.clone(); - } - - /** - * Prepare ants for the simulation - */ - private void setupAnts() { - IntStream.range(0, numberOfAnts).forEach(i -> { - ants.forEach(ant -> { - ant.clear(); - ant.visitCity(-1, random.nextInt(numberOfCities)); - }); - }); - currentIndex = 0; - } - - /** - * At each iteration, move ants - */ - private void moveAnts() { - IntStream.range(currentIndex, numberOfCities - 1).forEach(i -> { - ants.forEach(ant -> ant.visitCity(currentIndex, selectNextCity(ant))); - currentIndex++; - }); - } - - /** - * Select next city for each ant - */ - private int selectNextCity(Ant ant) { - int t = random.nextInt(numberOfCities - currentIndex); - if (random.nextDouble() < randomFactor) { - IntStream.range(0, numberOfCities).filter(i -> i == t && !ant.visited(i)).findFirst(); //TODO unused - } - calculateProbabilities(ant); - double r = random.nextDouble(); - double total = 0; - for (int i = 0; i < numberOfCities; i++) { - total += probabilities[i]; - if (total >= r) { - return i; - } - } - - throw new RuntimeException("There are no other cities"); - } - - /** - * Calculate the next city picks probabilites - */ - public void calculateProbabilities(Ant ant) { - int i = ant.trail[currentIndex]; - double pheromone = 0.0; - for (int l = 0; l < numberOfCities; l++) { - if (!ant.visited(l)) { - pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta); - } - } - for (int j = 0; j < numberOfCities; j++) { - if (ant.visited(j)) { - probabilities[j] = 0.0; - } else { - double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta); - probabilities[j] = numerator / pheromone; - } - } - } - - /** - * Update trails that ants used - */ - private void updateTrails() { - for (int i = 0; i < numberOfCities; i++) { - for (int j = 0; j < numberOfCities; j++) { - trails[i][j] *= evaporation; - } - } - for (Ant a : ants) { - double contribution = Q / a.trailLength(graph); - for (int i = 0; i < numberOfCities - 1; i++) { - trails[a.trail[i]][a.trail[i + 1]] += contribution; - } - trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution; - } - } - - /** - * Update the best solution - */ - private void updateBest() { - if (bestTourOrder == null) { - bestTourOrder = ants.get(0).trail; - bestTourLength = ants.get(0).trailLength(graph); - } - for (Ant a : ants) { - if (a.trailLength(graph) < bestTourLength) { - bestTourLength = a.trailLength(graph); - bestTourOrder = a.trail.clone(); - } - } - } - - /** - * Clear trails after simulation - */ - private void clearTrails() { - IntStream.range(0, numberOfCities).forEach(i -> { - IntStream.range(0, numberOfCities).forEach(j -> trails[i][j] = c); - }); - } - -} diff --git a/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java b/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java index 4137b5af00..10ceaf85a4 100644 --- a/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java +++ b/core-java/src/test/java/com/baeldung/PrimitiveConversionsJUnitTest.java @@ -1,4 +1,4 @@ -package com.baeldung.primitiveconversions; +package com.baeldung; import org.junit.Test; import static org.junit.Assert.*; From 6ea120d67fa2e8ffd4a3f3276125aa5d0d3cf39f Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Thu, 9 Mar 2017 13:03:30 +0530 Subject: [PATCH 068/291] Updating dependency and removing credentials (#1342) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * Twitter4J * Update Application.java * Update ApplicationTest.java * Update twitter4j.properties * Update pom.xml * Update Application.java --- Twitter4J/pom.xml | 5 ----- Twitter4J/src/main/java/com/baeldung/Application.java | 9 ++++----- core-java/0.004102810554955205 | 0 core-java/0.04832801936270381 | 0 core-java/0.5633433244738808 | 0 core-java/0.6256429734439612 | 0 core-java/0.9799201796740292 | 0 7 files changed, 4 insertions(+), 10 deletions(-) create mode 100644 core-java/0.004102810554955205 create mode 100644 core-java/0.04832801936270381 create mode 100644 core-java/0.5633433244738808 create mode 100644 core-java/0.6256429734439612 create mode 100644 core-java/0.9799201796740292 diff --git a/Twitter4J/pom.xml b/Twitter4J/pom.xml index ebe5a7d409..7e41d8de76 100644 --- a/Twitter4J/pom.xml +++ b/Twitter4J/pom.xml @@ -17,11 +17,6 @@ - - org.twitter4j - twitter4j-core - 4.0.6 - org.twitter4j twitter4j-stream diff --git a/Twitter4J/src/main/java/com/baeldung/Application.java b/Twitter4J/src/main/java/com/baeldung/Application.java index f7da27db29..3f961ccb4f 100644 --- a/Twitter4J/src/main/java/com/baeldung/Application.java +++ b/Twitter4J/src/main/java/com/baeldung/Application.java @@ -28,11 +28,10 @@ public class Application { */ // ConfigurationBuilder cb = new ConfigurationBuilder(); // cb.setDebugEnabled(true) -// .setOAuthConsumerKey("DPHTBsWWO42d8rzshxlK0OwSY") -// .setOAuthConsumerSecret("ACLXkeRY98NiaVCG1ai8fdYt0GoEGJbFeTuxjulSCO7sLKqls1") -// .setOAuthAccessToken("838080188214759428-9MSK1ddPTN5ZZHbddjFI7s75mYgmCFQ") -// .setOAuthAccessTokenSecret("1eXAADpHShAzQh5hGWLBUQHLysOuAKIOapmQQ8U0OVk2c"); -// +// .setOAuthConsumerKey("//TODO") +// .setOAuthConsumerSecret("//TODO") +// .setOAuthAccessToken("//TODO") +// .setOAuthAccessTokenSecret("//TODO"); // TwitterFactory tf = new TwitterFactory(cb.build()); // Twitter twitter = tf.getSingleton(); diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292 new file mode 100644 index 0000000000..e69de29bb2 From 00d42129ef505f9bdf4a96b02cc2037474faf116 Mon Sep 17 00:00:00 2001 From: Yasin Date: Thu, 9 Mar 2017 13:20:23 +0530 Subject: [PATCH 069/291] BAEL-608 - Introduction to Java9 StackWalking AP (#1329) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements --- .../java9/stackwalker/StackWalkerDemo.java | 44 ++++++++++++++----- .../stackwalker/StackWalkerDemoTest.java | 7 ++- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java b/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java index ee2cf092cd..a0e632d569 100644 --- a/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java +++ b/core-java-9/src/main/java/com/baeldung/java9/stackwalker/StackWalkerDemo.java @@ -16,48 +16,68 @@ public class StackWalkerDemo { } public void methodThree() { - List stackTrace = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) - .walk(StackWalkerDemo::walkExample); + List stackTrace = StackWalker.getInstance() + .walk(this::walkExample); printStackTrace(stackTrace); System.out.println("---------------------------------------------"); - stackTrace = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) - .walk(StackWalkerDemo::walkExample2); + stackTrace = StackWalker.getInstance() + .walk(this::walkExample2); printStackTrace(stackTrace); System.out.println("---------------------------------------------"); - String line = StackWalker.getInstance() - .walk(StackWalkerDemo::walkExample3); + String line = StackWalker.getInstance().walk(this::walkExample3); System.out.println(line); + + System.out.println("---------------------------------------------"); + + stackTrace = StackWalker.getInstance(StackWalker.Option.SHOW_REFLECT_FRAMES) + .walk(this::walkExample); + + printStackTrace(stackTrace); + + System.out.println("---------------------------------------------"); + + Runnable r = () -> { + List stackTrace2 = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES) + .walk(this::walkExample); + printStackTrace(stackTrace2); + }; + r.run(); } - private static List walkExample(Stream stackFrameStream) { + public List walkExample(Stream stackFrameStream) { return stackFrameStream.collect(Collectors.toList()); } - private static List walkExample2(Stream stackFrameStream) { + public List walkExample2(Stream stackFrameStream) { return stackFrameStream.filter(frame -> frame.getClassName() .contains("com.baeldung")) .collect(Collectors.toList()); } - private static String walkExample3(Stream stackFrameStream) { + public String walkExample3(Stream stackFrameStream) { return stackFrameStream.filter(frame -> frame.getClassName() .contains("com.baeldung") && frame.getClassName() - .endsWith("Test")) + .endsWith("Test")) .findFirst() .map(frame -> frame.getClassName() + "#" + frame.getMethodName() + ", Line " + frame.getLineNumber()) .orElse("Unknown caller"); } + + public void findCaller() { + Class caller = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); + System.out.println(caller.getCanonicalName()); + } - private void printStackTrace(List stackTrace) { + public void printStackTrace(List stackTrace) { for (StackFrame stackFrame : stackTrace) { - System.out.println(stackFrame.getDeclaringClass() + System.out.println(stackFrame.getClassName() .toString() + "#" + stackFrame.getMethodName() + ", Line " + stackFrame.getLineNumber()); } } diff --git a/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java b/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java index 61c8440b87..b523b7dfb2 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/stackwalker/StackWalkerDemoTest.java @@ -5,7 +5,12 @@ import org.junit.Test; public class StackWalkerDemoTest { @Test - public void walkTheStack() { + public void giveStalkWalker_whenWalkingTheStack_thenShowStackFrames() { new StackWalkerDemo().methodOne(); } + + @Test + public void giveStalkWalker_whenInvokingFindCaller_thenFindCallingClass() { + new StackWalkerDemo().findCaller(); + } } From a5f8bf91be368560d6534b308df8deb0f908b0cc Mon Sep 17 00:00:00 2001 From: baljeet20 Date: Thu, 9 Mar 2017 13:36:06 +0530 Subject: [PATCH 070/291] BAEL-707 Introduction to JiBX (#1340) --- xml/pom.xml | 233 +++++++++++++++++- .../java/com/baeldung/xml/jibx/Customer.java | 53 ++++ .../java/com/baeldung/xml/jibx/Identity.java | 14 ++ .../java/com/baeldung/xml/jibx/Person.java | 34 +++ .../java/com/baeldung/xml/jibx/Phone.java | 32 +++ xml/src/main/resources/Order.xsd | 49 ++++ xml/src/main/resources/customer-binding.xml | 29 +++ .../com/baeldung/xml/jibx/CustomerTest.java | 56 +++++ xml/src/test/resources/Customer1.xml | 21 ++ 9 files changed, 516 insertions(+), 5 deletions(-) create mode 100644 xml/src/main/java/com/baeldung/xml/jibx/Customer.java create mode 100644 xml/src/main/java/com/baeldung/xml/jibx/Identity.java create mode 100644 xml/src/main/java/com/baeldung/xml/jibx/Person.java create mode 100644 xml/src/main/java/com/baeldung/xml/jibx/Phone.java create mode 100644 xml/src/main/resources/Order.xsd create mode 100755 xml/src/main/resources/customer-binding.xml create mode 100644 xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java create mode 100644 xml/src/test/resources/Customer1.xml diff --git a/xml/pom.xml b/xml/pom.xml index 4230350ed9..38bf6bf42e 100644 --- a/xml/pom.xml +++ b/xml/pom.xml @@ -7,6 +7,32 @@ xml + + + jibx.sf.net + JiBX repository + http://jibx.sf.net/maven2 + + never + + + false + + + + + + jibx.sf.net + JiBX repository + http://jibx.sf.net/maven2 + + never + + + false + + + @@ -46,6 +72,17 @@ ${commons-lang3.version} + + org.jibx + jibx-run + ${jibx-version} + + + commons-lang + commons-lang + ${commons-lang.version} + + @@ -74,8 +111,8 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - 1.8 - 1.8 + ${java-version} + ${java-version} @@ -83,21 +120,206 @@ org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} + + + CustomerTest.java + + + + + schemaGen + + + + org.jibx + maven-jibx-plugin + ${maven-jibx-plugin.version} + + + generate-java-code-from-schema + + schema-codegen + + + src/main/resources + + Order.xsd + + true + + + + compile-binding + + bind + + + target/generated-sources + true + true + + true + + + + generate-test-code-from-schema + generate-test-sources + + test-schema-codegen + + + + compile-test-binding + process-test-classes + + test-bind + + + target/generated-test-sources + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java-version} + ${java-version} + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + CustomerTest.java + + + + + + + + + + bindGen + + + + + org.jibx + maven-jibx-plugin + + + + + + org.jibx + maven-jibx-plugin + ${maven-jibx-plugin.version} + + src/main/resources + + *-binding.xml + + + template-binding.xml + + true + + + + process-classes + + bind + + + + + + org.jibx + maven-jibx-plugin + 1.3.1 + + src/main/resources + + *-binding.xml + + true + + + + process-test-classes + + test-bind + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java-version} + ${java-version} + + + + + maven-assembly-plugin + + + + jar-with-dependencies + + + + + + com.baeldung.xml.jibx.JiBXDemoApplication + + + + + + + make-assembly + package + + attached + + + + + + + + + + - 1.6.1 - 1.1.6 - 2.0.6 + 1.6.1 + 1.1.6 + 2.0.6 2.5 4.1 + 1.2.4.5 3.5 + 2.4 + 1.8 4.12 @@ -105,6 +327,7 @@ 3.6.0 2.19.1 + 1.3.1 diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Customer.java b/xml/src/main/java/com/baeldung/xml/jibx/Customer.java new file mode 100644 index 0000000000..fabd464663 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/jibx/Customer.java @@ -0,0 +1,53 @@ +/* + * Customer.java 06.06.2008 + * + * Copyright 2008 Stefan Jäger + * + */ +package com.baeldung.xml.jibx; + +import org.apache.commons.lang.builder.ToStringBuilder; + +public class Customer { + private Person person; + private String city; + + private Phone homePhone; + private Phone officePhone; + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public Phone getHomePhone() { + return homePhone; + } + + public void setHomePhone(Phone homePhone) { + this.homePhone = homePhone; + } + + public Phone getOfficePhone() { + return officePhone; + } + + public void setOfficePhone(Phone officePhone) { + this.officePhone = officePhone; + } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Identity.java b/xml/src/main/java/com/baeldung/xml/jibx/Identity.java new file mode 100644 index 0000000000..15aab4e417 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/jibx/Identity.java @@ -0,0 +1,14 @@ +package com.baeldung.xml.jibx; + +public class Identity { + + long customerId; + + public long getCustomerId() { + return customerId; + } + + public void setCustomerId(long customerId) { + this.customerId = customerId; + } +} diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Person.java b/xml/src/main/java/com/baeldung/xml/jibx/Person.java new file mode 100644 index 0000000000..54ce75e257 --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/jibx/Person.java @@ -0,0 +1,34 @@ +/* + * Person.java 06.06.2008 + * + * Copyright 2008 Stefan Jäger + * + */ +package com.baeldung.xml.jibx; + +import org.apache.commons.lang.builder.ToStringBuilder; + +public class Person extends Identity { + private String firstName; + private String lastName; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Phone.java b/xml/src/main/java/com/baeldung/xml/jibx/Phone.java new file mode 100644 index 0000000000..b24950289a --- /dev/null +++ b/xml/src/main/java/com/baeldung/xml/jibx/Phone.java @@ -0,0 +1,32 @@ +package com.baeldung.xml.jibx; + +public class Phone { + + private String countryCode; + private String networkPrefix; + private String number; + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getNetworkPrefix() { + return networkPrefix; + } + + public void setNetworkPrefix(String networkPrefix) { + this.networkPrefix = networkPrefix; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } +} diff --git a/xml/src/main/resources/Order.xsd b/xml/src/main/resources/Order.xsd new file mode 100644 index 0000000000..16e689a342 --- /dev/null +++ b/xml/src/main/resources/Order.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xml/src/main/resources/customer-binding.xml b/xml/src/main/resources/customer-binding.xml new file mode 100755 index 0000000000..54ce4a925f --- /dev/null +++ b/xml/src/main/resources/customer-binding.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java b/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java new file mode 100644 index 0000000000..c678ce8406 --- /dev/null +++ b/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java @@ -0,0 +1,56 @@ +package com.baeldung.xml.jibx; + +import org.jibx.runtime.BindingDirectory; +import org.jibx.runtime.IBindingFactory; +import org.jibx.runtime.IUnmarshallingContext; +import org.jibx.runtime.JiBXException; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +import static junit.framework.Assert.assertEquals; + +public class CustomerTest { + + @Test + public void whenUnmarshalXML_ThenFieldsAreMapped() throws JiBXException, FileNotFoundException { + IBindingFactory bfact = BindingDirectory.getFactory(Customer.class); + IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream("Customer1.xml"); + Customer customer = (Customer) uctx.unmarshalDocument(inputStream, null); + + assertEquals("Stefan", customer.getPerson().getFirstName()); + assertEquals("Jaeger", customer.getPerson().getLastName()); + assertEquals("Davos Dorf", customer.getCity()); + + } + + @Test + public void WhenUnmarshal_ThenMappingInherited() throws JiBXException, FileNotFoundException { + IBindingFactory bfact = BindingDirectory.getFactory(Customer.class); + IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream("Customer1.xml"); + Customer customer = (Customer) uctx.unmarshalDocument(inputStream, null); + + assertEquals(12345, customer.getPerson().getCustomerId()); + + } + + @Test + public void WhenUnmarshal_ThenPhoneMappingRead() throws JiBXException, FileNotFoundException { + IBindingFactory bfact = BindingDirectory.getFactory(Customer.class); + IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream("Customer1.xml"); + Customer customer = (Customer) uctx.unmarshalDocument(inputStream, null); + + assertEquals("1", customer.getHomePhone().getCountryCode()); + assertEquals("234", customer.getHomePhone().getNetworkPrefix()); + assertEquals("234678", customer.getHomePhone().getNumber()); + + } +} diff --git a/xml/src/test/resources/Customer1.xml b/xml/src/test/resources/Customer1.xml new file mode 100644 index 0000000000..3941563ffe --- /dev/null +++ b/xml/src/test/resources/Customer1.xml @@ -0,0 +1,21 @@ + + + + 12345 + Stefan + Jaeger + + + 1 + 234 + 234678 + + + + 1 + 234 + 234678 + + Davos Dorf + + \ No newline at end of file From 2cc336e0cbf6c013b55eecc71a28abc936b230fa Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Thu, 9 Mar 2017 11:32:17 +0100 Subject: [PATCH 071/291] ESG-606 - refining tests --- .../com/baeldung/money/JavaMoneyTest.java | 149 ++++++++---------- 1 file changed, 67 insertions(+), 82 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java index d1992969f2..140560d079 100644 --- a/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java +++ b/core-java/src/test/java/com/baeldung/money/JavaMoneyTest.java @@ -43,10 +43,10 @@ public class JavaMoneyTest { public void givenAmounts_whenStringified_thanEquals() { CurrencyUnit usd = Monetary.getCurrency("USD"); MonetaryAmount fstAmtUSD = Monetary - .getDefaultAmountFactory() - .setCurrency(usd) - .setNumber(200) - .create(); + .getDefaultAmountFactory() + .setCurrency(usd) + .setNumber(200) + .create(); Money moneyof = Money.of(12, usd); FastMoney fastmoneyof = FastMoney.of(2, usd); @@ -59,10 +59,10 @@ public class JavaMoneyTest { @Test public void givenCurrencies_whenCompared_thanNotequal() { MonetaryAmount oneDolar = Monetary - .getDefaultAmountFactory() - .setCurrency("USD") - .setNumber(1) - .create(); + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); Money oneEuro = Money.of(1, "EUR"); assertFalse(oneEuro.equals(FastMoney.of(1, "EUR"))); @@ -72,10 +72,10 @@ public class JavaMoneyTest { @Test(expected = ArithmeticException.class) public void givenAmount_whenDivided_thanThrowsException() { MonetaryAmount oneDolar = Monetary - .getDefaultAmountFactory() - .setCurrency("USD") - .setNumber(1) - .create(); + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); oneDolar.divide(3); fail(); // if no exception } @@ -85,8 +85,8 @@ public class JavaMoneyTest { List monetaryAmounts = Arrays.asList(Money.of(100, "CHF"), Money.of(10.20, "CHF"), Money.of(1.15, "CHF")); Money sumAmtCHF = (Money) monetaryAmounts - .stream() - .reduce(Money.of(0, "CHF"), MonetaryAmount::add); + .stream() + .reduce(Money.of(0, "CHF"), MonetaryAmount::add); assertEquals("CHF 111.35", sumAmtCHF.toString()); } @@ -97,18 +97,18 @@ public class JavaMoneyTest { Money moneyof = Money.of(12, usd); MonetaryAmount fstAmtUSD = Monetary - .getDefaultAmountFactory() - .setCurrency(usd) - .setNumber(200.50) - .create(); + .getDefaultAmountFactory() + .setCurrency(usd) + .setNumber(200.50) + .create(); MonetaryAmount oneDolar = Monetary - .getDefaultAmountFactory() - .setCurrency("USD") - .setNumber(1) - .create(); + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); Money subtractedAmount = Money - .of(1, "USD") - .subtract(fstAmtUSD); + .of(1, "USD") + .subtract(fstAmtUSD); MonetaryAmount multiplyAmount = oneDolar.multiply(0.25); MonetaryAmount divideAmount = oneDolar.divide(0.25); @@ -124,78 +124,63 @@ public class JavaMoneyTest { @Test public void givenAmount_whenRounded_thanEquals() { MonetaryAmount fstAmtEUR = Monetary - .getDefaultAmountFactory() - .setCurrency("EUR") - .setNumber(1.30473908) - .create(); + .getDefaultAmountFactory() + .setCurrency("EUR") + .setNumber(1.30473908) + .create(); MonetaryAmount roundEUR = fstAmtEUR.with(Monetary.getDefaultRounding()); assertEquals("EUR 1.30473908", fstAmtEUR.toString()); assertEquals("EUR 1.3", roundEUR.toString()); } @Test - public void givenAmount_whenCustomFormat_thanEquals() { - MonetaryAmount oneDolar = Monetary - .getDefaultAmountFactory() - .setCurrency("USD") - .setNumber(1) - .create(); - MonetaryAmountFormat formatUSD = MonetaryFormats.getAmountFormat(Locale.US); - String usFormatted = formatUSD.format(oneDolar); + public void givenAmount_whenConversion_thenNotNull() { + MonetaryAmount oneDollar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); - MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder - .of(Locale.US) - .set(CurrencyStyle.NAME) - .set("pattern", "00000.00 ¤") - .build()); - String customFormatted = customFormat.format(oneDolar); + CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR"); - assertEquals("USD 1", oneDolar.toString()); - assertNotNull(formatUSD); - assertNotNull(customFormat); - assertEquals("USD1.00", usFormatted); - assertEquals("00001.00 US Dollar", customFormatted); + MonetaryAmount convertedAmountUSDtoEUR = oneDollar.with(conversionEUR); + + assertEquals("USD 1", oneDollar.toString()); + assertNotNull(convertedAmountUSDtoEUR); } @Test - public void givenAmount_whenConversion_thenNotNull() { - CurrencyUnit USD = Monetary.getCurrency("USD"); - MonetaryAmount oneDolar = Monetary - .getDefaultAmountFactory() - .setCurrency("USD") - .setNumber(1) - .create(); - MonetaryAmount fstAmtEUR = Monetary - .getDefaultAmountFactory() - .setCurrency("EUR") - .setNumber(1.30473908) - .create(); + public void givenLocale_whenFormatted_thanEquals() { + MonetaryAmount oneDollar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); + MonetaryAmountFormat formatUSD = MonetaryFormats.getAmountFormat(Locale.US); + String usFormatted = formatUSD.format(oneDollar); - CurrencyConversion convEUR = MonetaryConversions.getConversion(ConversionQueryBuilder - .of() - .setTermCurrency("EUR") - .build()); - CurrencyConversion convUSD = MonetaryConversions.getConversion(ConversionQueryBuilder - .of() - .setTermCurrency(USD) - .build()); + assertEquals("USD 1", oneDollar.toString()); + assertNotNull(formatUSD); + assertEquals("USD1.00", usFormatted); + } - CurrencyConversion conversionUSD = MonetaryConversions.getConversion("USD"); - CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR"); + @Test + public void givenAmount_whenCustomFormat_thanEquals() { + MonetaryAmount oneDollar = Monetary + .getDefaultAmountFactory() + .setCurrency("USD") + .setNumber(1) + .create(); - MonetaryAmount convertedAmountEURtoUSD = fstAmtEUR.with(conversionUSD); - MonetaryAmount convertedAmountEURtoUSD2 = fstAmtEUR.with(convUSD); - MonetaryAmount convertedAmountUSDtoEUR = oneDolar.with(conversionEUR); - MonetaryAmount convertedAmountUSDtoEUR2 = oneDolar.with(convEUR); + MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder + .of(Locale.US) + .set(CurrencyStyle.NAME) + .set("pattern", "00000.00 ¤") + .build()); + String customFormatted = customFormat.format(oneDollar); - assertEquals("USD", USD.toString()); - assertEquals("USD 1", oneDolar.toString()); - assertEquals("EUR 1.30473908", fstAmtEUR.toString()); - assertNotNull(convEUR); - assertNotNull(convUSD); - assertNotNull(convertedAmountEURtoUSD); - assertNotNull(convertedAmountEURtoUSD2); - assertNotNull(convertedAmountUSDtoEUR); - assertNotNull(convertedAmountUSDtoEUR2); + assertNotNull(customFormat); + assertEquals("USD 1", oneDollar.toString()); + assertEquals("00001.00 US Dollar", customFormatted); } } From 273394fe4e686d970e53d512a20da62f9f11b013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20G=C3=B3mez?= Date: Thu, 9 Mar 2017 07:06:51 -0600 Subject: [PATCH 072/291] Hibernate immutable (#1333) * Add project for hibernate immutable article Add Event entity Add hibernate configuration file Add hibernateutil for configuration Add test to match snippets from article * Create README.md * Update README.md * Migrate hibernate-immutable to spring-hibernate-4 Include integration test Add immutable.cfg.xml Include util for configuration * Remove project for hibernate-immutable --- .../hibernate/immutable/entities/Event.java | 58 +++++++++++++ .../immutable/util/HibernateUtil.java | 29 +++++++ .../src/main/resources/immutable.cfg.xml | 38 +++++++++ .../HibernateImmutableIntegrationTest.java | 84 +++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java create mode 100644 spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java create mode 100644 spring-hibernate4/src/main/resources/immutable.cfg.xml create mode 100644 spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java diff --git a/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java b/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java new file mode 100644 index 0000000000..69cedd39d3 --- /dev/null +++ b/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java @@ -0,0 +1,58 @@ +package com.baeldung.hibernate.immutable.entities; + +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.CascadeType; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Immutable; + +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Set; + +@Entity +@Immutable +@Table(name = "events") +public class Event { + + @Id + @Column(name = "event_id") + @GeneratedValue(generator = "increment") + @GenericGenerator(name = "increment", strategy = "increment") + private Long id; + + @Column(name = "title") + private String title; + + @ElementCollection + @Immutable + private Set guestList; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) + public Set getGuestList() { + return guestList; + } + + public void setGuestList(Set guestList) { + this.guestList = guestList; + } +} diff --git a/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java b/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java new file mode 100644 index 0000000000..0918ff105a --- /dev/null +++ b/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.immutable.util; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.service.ServiceRegistry; + +public class HibernateUtil { + private static final SessionFactory sessionFactory = buildSessionFactory(); + + private static SessionFactory buildSessionFactory() { + try { + // Create a session factory from immutable.cfg.xml + Configuration configuration = new Configuration(); + configuration.configure("immutable.cfg.xml"); + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + return configuration.buildSessionFactory(serviceRegistry); + } catch (Throwable ex) { + System.out.println("Initial SessionFactory creation failed." + ex); + throw new ExceptionInInitializerError(ex); + } + } + + public static SessionFactory getSessionFactory() { + return sessionFactory; + } +} diff --git a/spring-hibernate4/src/main/resources/immutable.cfg.xml b/spring-hibernate4/src/main/resources/immutable.cfg.xml new file mode 100644 index 0000000000..fe1e3cb723 --- /dev/null +++ b/spring-hibernate4/src/main/resources/immutable.cfg.xml @@ -0,0 +1,38 @@ + + + + + + + + + org.hsqldb.jdbcDriver + jdbc:hsqldb:hsql:mem://localhost/xdb + sa + + + + 1 + + + org.hibernate.dialect.HSQLDialect + + + thread + + + org.hibernate.cache.NoCacheProvider + + + true + + + update + + + + + + \ No newline at end of file diff --git a/spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java b/spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java new file mode 100644 index 0000000000..83a2fd3cb8 --- /dev/null +++ b/spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java @@ -0,0 +1,84 @@ +package com.baeldung.hibernate.immutable; + +import com.baeldung.hibernate.immutable.entities.Event; +import com.baeldung.hibernate.immutable.util.HibernateUtil; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class HibernateImmutableIntegrationTest { + private Session session; + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Before + public void setup() { + session = HibernateUtil.getSessionFactory().getCurrentSession(); + session.beginTransaction(); + createEvent(); + } + + @After + public void teardown() { + HibernateUtil.getSessionFactory().close(); + } + + @Test + public void addEvent() { + Event event = new Event(); + event.setTitle("Public Event"); + session.save(event); + session.getTransaction().commit(); + } + + @Test + public void updateEvent() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='My Event'").list().get(0); + event.setTitle("Private Event"); + session.saveOrUpdate(event); + session.getTransaction().commit(); + } + + @Test + public void deleteEvent() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='My Event'").list().get(0); + session.delete(event); + session.getTransaction().commit(); + } + + @Test + public void addGuest() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='New Event'").list().get(0); + String newGuest = "Sara"; + event.getGuestList().add(newGuest); + + exception.expect(HibernateException.class); + session.save(event); + session.getTransaction().commit(); + } + + @Test + public void deleteCascade() { + Event event = (Event) session.createQuery( + "FROM Event WHERE title='New Event'").list().get(0); + String guest = event.getGuestList().iterator().next(); + event.getGuestList().remove(guest); + + exception.expect(HibernateException.class); + session.saveOrUpdate(event); + session.getTransaction().commit(); + } + + public void createEvent() { + Event event = new Event(); + event.setTitle("New Event"); + session.save(event); + } +} From 8dcb9af71200c4ea4a9c8bf18a172783582014c4 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Thu, 9 Mar 2017 15:59:18 +0100 Subject: [PATCH 073/291] BAEL-518 google protocol buffers * BEEL-518 code for protobuf article * BEEL-518 add generated protobuf class * BAEL-701 updated the method argument * BEEL-550 use newest version of protobuff * Bael 389 - Building URL dynamically between host and pathname (#1323) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces * BAEL-389 - Building URL dynamically between host and pathname * Rename classes (#1331) * BAEL-550 Axon framework * BEEL-550 create axon module * BEEL-550 proper naming * BEEL-550 better example of message service * BEEL-550 proper name of method * BEEL-550 remove not needed comments * BEEL-550 proper message * BEEL-550 axon test scope test * BEEL-550 tries to migrate to axon 3 * BEEL-550 migrate to vesrion 3 successfull * ACO refactor * BAEL-518 Small refactoring in protobuffer module --- pom.xml | 2 +- protobuffer/pom.xml | 48 + .../baeldung/protobuf/AddressBookProtos.java | 2989 +++++++++++++++++ .../src/main/resources/addressbook.proto | 27 + .../com/baeldung/protobuf/ProtobufTest.java | 90 + 5 files changed, 3155 insertions(+), 1 deletion(-) create mode 100644 protobuffer/pom.xml create mode 100644 protobuffer/src/main/java/com/baeldung/protobuf/AddressBookProtos.java create mode 100644 protobuffer/src/main/resources/addressbook.proto create mode 100644 protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java diff --git a/pom.xml b/pom.xml index ce66ff4159..de025d3b4f 100644 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,7 @@ patterns pdf + protobuffer querydsl @@ -204,7 +205,6 @@ rabbitmq - diff --git a/protobuffer/pom.xml b/protobuffer/pom.xml new file mode 100644 index 0000000000..17394716e2 --- /dev/null +++ b/protobuffer/pom.xml @@ -0,0 +1,48 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + protobuffer + + + + com.google.protobuf + protobuf-java + ${protobuf.version} + + + junit + junit + ${junit.version} + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + + + + 3.2.0 + 4.12 + 3.6.0 + + + \ No newline at end of file diff --git a/protobuffer/src/main/java/com/baeldung/protobuf/AddressBookProtos.java b/protobuffer/src/main/java/com/baeldung/protobuf/AddressBookProtos.java new file mode 100644 index 0000000000..c39b4e42b9 --- /dev/null +++ b/protobuffer/src/main/java/com/baeldung/protobuf/AddressBookProtos.java @@ -0,0 +1,2989 @@ +/// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: routeguide.proto + +package com.baeldung.protobuf; + +public final class AddressBookProtos { + private AddressBookProtos() { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + public interface PersonOrBuilder extends + // @@protoc_insertion_point(interface_extends:protobuf.Person) + com.google.protobuf.MessageOrBuilder { + + /** + * required string name = 1; + */ + boolean hasName(); + + /** + * required string name = 1; + */ + java.lang.String getName(); + + /** + * required string name = 1; + */ + com.google.protobuf.ByteString + getNameBytes(); + + /** + * required int32 id = 2; + */ + boolean hasId(); + + /** + * required int32 id = 2; + */ + int getId(); + + /** + * optional string email = 3; + */ + boolean hasEmail(); + + /** + * optional string email = 3; + */ + java.lang.String getEmail(); + + /** + * optional string email = 3; + */ + com.google.protobuf.ByteString + getEmailBytes(); + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + java.util.List + getPhonesList(); + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + AddressBookProtos.Person.PhoneNumber getPhones(int index); + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + int getPhonesCount(); + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + java.util.List + getPhonesOrBuilderList(); + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index); + } + + /** + * Protobuf type {@code protobuf.Person} + */ + public static final class Person extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protobuf.Person) + PersonOrBuilder { + // Use Person.newBuilder() to construct. + private Person(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private Person() { + name_ = ""; + id_ = 0; + email_ = ""; + phones_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private Person( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + name_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + id_ = input.readInt32(); + break; + } + case 26: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + email_ = bs; + break; + } + case 34: { + if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + phones_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000008; + } + phones_.add( + input.readMessage(AddressBookProtos.Person.PhoneNumber.PARSER, extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { + phones_ = java.util.Collections.unmodifiableList(phones_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_Person_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.Person.class, AddressBookProtos.Person.Builder.class); + } + + /** + * Protobuf enum {@code protobuf.Person.PhoneType} + */ + public enum PhoneType + implements com.google.protobuf.ProtocolMessageEnum { + /** + * MOBILE = 0; + */ + MOBILE(0), + /** + * HOME = 1; + */ + HOME(1), + /** + * WORK = 2; + */ + WORK(2),; + + /** + * MOBILE = 0; + */ + public static final int MOBILE_VALUE = 0; + /** + * HOME = 1; + */ + public static final int HOME_VALUE = 1; + /** + * WORK = 2; + */ + public static final int WORK_VALUE = 2; + + + public final int getNumber() { + return value; + } + + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static PhoneType valueOf(int value) { + return forNumber(value); + } + + public static PhoneType forNumber(int value) { + switch (value) { + case 0: + return MOBILE; + case 1: + return HOME; + case 2: + return WORK; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap< + PhoneType> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public PhoneType findValueByNumber(int number) { + return PhoneType.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(ordinal()); + } + + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return AddressBookProtos.Person.getDescriptor().getEnumTypes().get(0); + } + + private static final PhoneType[] VALUES = values(); + + public static PhoneType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private PhoneType(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:protobuf.Person.PhoneType) + } + + public interface PhoneNumberOrBuilder extends + // @@protoc_insertion_point(interface_extends:protobuf.Person.PhoneNumber) + com.google.protobuf.MessageOrBuilder { + + /** + * required string number = 1; + */ + boolean hasNumber(); + + /** + * required string number = 1; + */ + java.lang.String getNumber(); + + /** + * required string number = 1; + */ + com.google.protobuf.ByteString + getNumberBytes(); + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + boolean hasType(); + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + AddressBookProtos.Person.PhoneType getType(); + } + + /** + * Protobuf type {@code protobuf.Person.PhoneNumber} + */ + public static final class PhoneNumber extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protobuf.Person.PhoneNumber) + PhoneNumberOrBuilder { + // Use PhoneNumber.newBuilder() to construct. + private PhoneNumber(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private PhoneNumber() { + number_ = ""; + type_ = 1; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private PhoneNumber( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + number_ = bs; + break; + } + case 16: { + int rawValue = input.readEnum(); + AddressBookProtos.Person.PhoneType value = AddressBookProtos.Person.PhoneType.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(2, rawValue); + } else { + bitField0_ |= 0x00000002; + type_ = rawValue; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.Person.PhoneNumber.class, AddressBookProtos.Person.PhoneNumber.Builder.class); + } + + private int bitField0_; + public static final int NUMBER_FIELD_NUMBER = 1; + private volatile java.lang.Object number_; + + /** + * required string number = 1; + */ + public boolean hasNumber() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + + /** + * required string number = 1; + */ + public java.lang.String getNumber() { + java.lang.Object ref = number_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + number_ = s; + } + return s; + } + } + + /** + * required string number = 1; + */ + public com.google.protobuf.ByteString + getNumberBytes() { + java.lang.Object ref = number_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + number_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TYPE_FIELD_NUMBER = 2; + private int type_; + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public boolean hasType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public AddressBookProtos.Person.PhoneType getType() { + AddressBookProtos.Person.PhoneType result = AddressBookProtos.Person.PhoneType.valueOf(type_); + return result == null ? AddressBookProtos.Person.PhoneType.HOME : result; + } + + private byte memoizedIsInitialized = -1; + + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasNumber()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, number_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, type_); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, number_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, type_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AddressBookProtos.Person.PhoneNumber)) { + return super.equals(obj); + } + AddressBookProtos.Person.PhoneNumber other = (AddressBookProtos.Person.PhoneNumber) obj; + + boolean result = true; + result = result && (hasNumber() == other.hasNumber()); + if (hasNumber()) { + result = result && getNumber() + .equals(other.getNumber()); + } + result = result && (hasType() == other.hasType()); + if (hasType()) { + result = result && type_ == other.type_; + } + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (hasNumber()) { + hash = (37 * hash) + NUMBER_FIELD_NUMBER; + hash = (53 * hash) + getNumber().hashCode(); + } + if (hasType()) { + hash = (37 * hash) + TYPE_FIELD_NUMBER; + hash = (53 * hash) + type_; + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.Person.PhoneNumber parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person.PhoneNumber parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person.PhoneNumber parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(AddressBookProtos.Person.PhoneNumber prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code protobuf.Person.PhoneNumber} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protobuf.Person.PhoneNumber) + AddressBookProtos.Person.PhoneNumberOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.Person.PhoneNumber.class, AddressBookProtos.Person.PhoneNumber.Builder.class); + } + + // Construct using AddressBookProtos.Person.PhoneNumber.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + public Builder clear() { + super.clear(); + number_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + type_ = 1; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; + } + + public AddressBookProtos.Person.PhoneNumber getDefaultInstanceForType() { + return AddressBookProtos.Person.PhoneNumber.getDefaultInstance(); + } + + public AddressBookProtos.Person.PhoneNumber build() { + AddressBookProtos.Person.PhoneNumber result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public AddressBookProtos.Person.PhoneNumber buildPartial() { + AddressBookProtos.Person.PhoneNumber result = new AddressBookProtos.Person.PhoneNumber(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.number_ = number_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.type_ = type_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof AddressBookProtos.Person.PhoneNumber) { + return mergeFrom((AddressBookProtos.Person.PhoneNumber) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(AddressBookProtos.Person.PhoneNumber other) { + if (other == AddressBookProtos.Person.PhoneNumber.getDefaultInstance()) + return this; + if (other.hasNumber()) { + bitField0_ |= 0x00000001; + number_ = other.number_; + onChanged(); + } + if (other.hasType()) { + setType(other.getType()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + if (!hasNumber()) { + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + AddressBookProtos.Person.PhoneNumber parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (AddressBookProtos.Person.PhoneNumber) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private java.lang.Object number_ = ""; + + /** + * required string number = 1; + */ + public boolean hasNumber() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + + /** + * required string number = 1; + */ + public java.lang.String getNumber() { + java.lang.Object ref = number_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + number_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * required string number = 1; + */ + public com.google.protobuf.ByteString + getNumberBytes() { + java.lang.Object ref = number_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + number_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * required string number = 1; + */ + public Builder setNumber( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + number_ = value; + onChanged(); + return this; + } + + /** + * required string number = 1; + */ + public Builder clearNumber() { + bitField0_ = (bitField0_ & ~0x00000001); + number_ = getDefaultInstance().getNumber(); + onChanged(); + return this; + } + + /** + * required string number = 1; + */ + public Builder setNumberBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + number_ = value; + onChanged(); + return this; + } + + private int type_ = 1; + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public boolean hasType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public AddressBookProtos.Person.PhoneType getType() { + AddressBookProtos.Person.PhoneType result = AddressBookProtos.Person.PhoneType.valueOf(type_); + return result == null ? AddressBookProtos.Person.PhoneType.HOME : result; + } + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public Builder setType(AddressBookProtos.Person.PhoneType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + type_ = value.getNumber(); + onChanged(); + return this; + } + + /** + * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; + */ + public Builder clearType() { + bitField0_ = (bitField0_ & ~0x00000002); + type_ = 1; + onChanged(); + return this; + } + + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:protobuf.Person.PhoneNumber) + } + + // @@protoc_insertion_point(class_scope:protobuf.Person.PhoneNumber) + private static final AddressBookProtos.Person.PhoneNumber DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new AddressBookProtos.Person.PhoneNumber(); + } + + public static AddressBookProtos.Person.PhoneNumber getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated + public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public PhoneNumber parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new PhoneNumber(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public AddressBookProtos.Person.PhoneNumber getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private int bitField0_; + public static final int NAME_FIELD_NUMBER = 1; + private volatile java.lang.Object name_; + + /** + * required string name = 1; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + + /** + * required string name = 1; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } + } + + /** + * required string name = 1; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int ID_FIELD_NUMBER = 2; + private int id_; + + /** + * required int32 id = 2; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + + /** + * required int32 id = 2; + */ + public int getId() { + return id_; + } + + public static final int EMAIL_FIELD_NUMBER = 3; + private volatile java.lang.Object email_; + + /** + * optional string email = 3; + */ + public boolean hasEmail() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + + /** + * optional string email = 3; + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + email_ = s; + } + return s; + } + } + + /** + * optional string email = 3; + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int PHONES_FIELD_NUMBER = 4; + private java.util.List phones_; + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List getPhonesList() { + return phones_; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List + getPhonesOrBuilderList() { + return phones_; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public int getPhonesCount() { + return phones_.size(); + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumber getPhones(int index) { + return phones_.get(index); + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index) { + return phones_.get(index); + } + + private byte memoizedIsInitialized = -1; + + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasId()) { + memoizedIsInitialized = 0; + return false; + } + for (int i = 0; i < getPhonesCount(); i++) { + if (!getPhones(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeInt32(2, id_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); + } + for (int i = 0; i < phones_.size(); i++) { + output.writeMessage(4, phones_.get(i)); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, id_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); + } + for (int i = 0; i < phones_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, phones_.get(i)); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AddressBookProtos.Person)) { + return super.equals(obj); + } + AddressBookProtos.Person other = (AddressBookProtos.Person) obj; + + boolean result = true; + result = result && (hasName() == other.hasName()); + if (hasName()) { + result = result && getName() + .equals(other.getName()); + } + result = result && (hasId() == other.hasId()); + if (hasId()) { + result = result && (getId() + == other.getId()); + } + result = result && (hasEmail() == other.hasEmail()); + if (hasEmail()) { + result = result && getEmail() + .equals(other.getEmail()); + } + result = result && getPhonesList() + .equals(other.getPhonesList()); + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (hasName()) { + hash = (37 * hash) + NAME_FIELD_NUMBER; + hash = (53 * hash) + getName().hashCode(); + } + if (hasId()) { + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + } + if (hasEmail()) { + hash = (37 * hash) + EMAIL_FIELD_NUMBER; + hash = (53 * hash) + getEmail().hashCode(); + } + if (getPhonesCount() > 0) { + hash = (37 * hash) + PHONES_FIELD_NUMBER; + hash = (53 * hash) + getPhonesList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static AddressBookProtos.Person parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.Person parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.Person parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.Person parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.Person parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.Person parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.Person parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.Person parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(AddressBookProtos.Person prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code protobuf.Person} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protobuf.Person) + AddressBookProtos.PersonOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_Person_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.Person.class, AddressBookProtos.Person.Builder.class); + } + + // Construct using AddressBookProtos.Person.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getPhonesFieldBuilder(); + } + } + + public Builder clear() { + super.clear(); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + email_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + if (phonesBuilder_ == null) { + phones_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + } else { + phonesBuilder_.clear(); + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return AddressBookProtos.internal_static_protobuf_Person_descriptor; + } + + public AddressBookProtos.Person getDefaultInstanceForType() { + return AddressBookProtos.Person.getDefaultInstance(); + } + + public AddressBookProtos.Person build() { + AddressBookProtos.Person result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public AddressBookProtos.Person buildPartial() { + AddressBookProtos.Person result = new AddressBookProtos.Person(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.name_ = name_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.id_ = id_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.email_ = email_; + if (phonesBuilder_ == null) { + if (((bitField0_ & 0x00000008) == 0x00000008)) { + phones_ = java.util.Collections.unmodifiableList(phones_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.phones_ = phones_; + } else { + result.phones_ = phonesBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof AddressBookProtos.Person) { + return mergeFrom((AddressBookProtos.Person) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(AddressBookProtos.Person other) { + if (other == AddressBookProtos.Person.getDefaultInstance()) return this; + if (other.hasName()) { + bitField0_ |= 0x00000001; + name_ = other.name_; + onChanged(); + } + if (other.hasId()) { + setId(other.getId()); + } + if (other.hasEmail()) { + bitField0_ |= 0x00000004; + email_ = other.email_; + onChanged(); + } + if (phonesBuilder_ == null) { + if (!other.phones_.isEmpty()) { + if (phones_.isEmpty()) { + phones_ = other.phones_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensurePhonesIsMutable(); + phones_.addAll(other.phones_); + } + onChanged(); + } + } else { + if (!other.phones_.isEmpty()) { + if (phonesBuilder_.isEmpty()) { + phonesBuilder_.dispose(); + phonesBuilder_ = null; + phones_ = other.phones_; + bitField0_ = (bitField0_ & ~0x00000008); + phonesBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getPhonesFieldBuilder() : null; + } else { + phonesBuilder_.addAllMessages(other.phones_); + } + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + if (!hasName()) { + return false; + } + if (!hasId()) { + return false; + } + for (int i = 0; i < getPhonesCount(); i++) { + if (!getPhones(i).isInitialized()) { + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + AddressBookProtos.Person parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (AddressBookProtos.Person) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private java.lang.Object name_ = ""; + + /** + * required string name = 1; + */ + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + + /** + * required string name = 1; + */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * required string name = 1; + */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * required string name = 1; + */ + public Builder setName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + return this; + } + + /** + * required string name = 1; + */ + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000001); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + + /** + * required string name = 1; + */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + return this; + } + + private int id_; + + /** + * required int32 id = 2; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + + /** + * required int32 id = 2; + */ + public int getId() { + return id_; + } + + /** + * required int32 id = 2; + */ + public Builder setId(int value) { + bitField0_ |= 0x00000002; + id_ = value; + onChanged(); + return this; + } + + /** + * required int32 id = 2; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000002); + id_ = 0; + onChanged(); + return this; + } + + private java.lang.Object email_ = ""; + + /** + * optional string email = 3; + */ + public boolean hasEmail() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + + /** + * optional string email = 3; + */ + public java.lang.String getEmail() { + java.lang.Object ref = email_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + email_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * optional string email = 3; + */ + public com.google.protobuf.ByteString + getEmailBytes() { + java.lang.Object ref = email_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + email_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * optional string email = 3; + */ + public Builder setEmail( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + email_ = value; + onChanged(); + return this; + } + + /** + * optional string email = 3; + */ + public Builder clearEmail() { + bitField0_ = (bitField0_ & ~0x00000004); + email_ = getDefaultInstance().getEmail(); + onChanged(); + return this; + } + + /** + * optional string email = 3; + */ + public Builder setEmailBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + email_ = value; + onChanged(); + return this; + } + + private java.util.List phones_ = + java.util.Collections.emptyList(); + + private void ensurePhonesIsMutable() { + if (!((bitField0_ & 0x00000008) == 0x00000008)) { + phones_ = new java.util.ArrayList(phones_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder> phonesBuilder_; + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List getPhonesList() { + if (phonesBuilder_ == null) { + return java.util.Collections.unmodifiableList(phones_); + } else { + return phonesBuilder_.getMessageList(); + } + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public int getPhonesCount() { + if (phonesBuilder_ == null) { + return phones_.size(); + } else { + return phonesBuilder_.getCount(); + } + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumber getPhones(int index) { + if (phonesBuilder_ == null) { + return phones_.get(index); + } else { + return phonesBuilder_.getMessage(index); + } + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder setPhones( + int index, AddressBookProtos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.set(index, value); + onChanged(); + } else { + phonesBuilder_.setMessage(index, value); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder setPhones( + int index, AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.set(index, builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones(AddressBookProtos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.add(value); + onChanged(); + } else { + phonesBuilder_.addMessage(value); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + int index, AddressBookProtos.Person.PhoneNumber value) { + if (phonesBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePhonesIsMutable(); + phones_.add(index, value); + onChanged(); + } else { + phonesBuilder_.addMessage(index, value); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.add(builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.addMessage(builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addPhones( + int index, AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.add(index, builderForValue.build()); + onChanged(); + } else { + phonesBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder addAllPhones( + java.lang.Iterable values) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, phones_); + onChanged(); + } else { + phonesBuilder_.addAllMessages(values); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder clearPhones() { + if (phonesBuilder_ == null) { + phones_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + phonesBuilder_.clear(); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public Builder removePhones(int index) { + if (phonesBuilder_ == null) { + ensurePhonesIsMutable(); + phones_.remove(index); + onChanged(); + } else { + phonesBuilder_.remove(index); + } + return this; + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumber.Builder getPhonesBuilder( + int index) { + return getPhonesFieldBuilder().getBuilder(index); + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( + int index) { + if (phonesBuilder_ == null) { + return phones_.get(index); + } else { + return phonesBuilder_.getMessageOrBuilder(index); + } + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List + getPhonesOrBuilderList() { + if (phonesBuilder_ != null) { + return phonesBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(phones_); + } + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumber.Builder addPhonesBuilder() { + return getPhonesFieldBuilder().addBuilder( + AddressBookProtos.Person.PhoneNumber.getDefaultInstance()); + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public AddressBookProtos.Person.PhoneNumber.Builder addPhonesBuilder( + int index) { + return getPhonesFieldBuilder().addBuilder( + index, AddressBookProtos.Person.PhoneNumber.getDefaultInstance()); + } + + /** + * repeated .protobuf.Person.PhoneNumber phones = 4; + */ + public java.util.List + getPhonesBuilderList() { + return getPhonesFieldBuilder().getBuilderList(); + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder> + getPhonesFieldBuilder() { + if (phonesBuilder_ == null) { + phonesBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder>( + phones_, + ((bitField0_ & 0x00000008) == 0x00000008), + getParentForChildren(), + isClean()); + phones_ = null; + } + return phonesBuilder_; + } + + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:protobuf.Person) + } + + // @@protoc_insertion_point(class_scope:protobuf.Person) + private static final AddressBookProtos.Person DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new AddressBookProtos.Person(); + } + + public static AddressBookProtos.Person getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated + public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public Person parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Person(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public AddressBookProtos.Person getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface AddressBookOrBuilder extends + // @@protoc_insertion_point(interface_extends:protobuf.AddressBook) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .protobuf.Person people = 1; + */ + java.util.List + getPeopleList(); + + /** + * repeated .protobuf.Person people = 1; + */ + AddressBookProtos.Person getPeople(int index); + + /** + * repeated .protobuf.Person people = 1; + */ + int getPeopleCount(); + + /** + * repeated .protobuf.Person people = 1; + */ + java.util.List + getPeopleOrBuilderList(); + + /** + * repeated .protobuf.Person people = 1; + */ + AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + int index); + } + + /** + * Protobuf type {@code protobuf.AddressBook} + */ + public static final class AddressBook extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:protobuf.AddressBook) + AddressBookOrBuilder { + // Use AddressBook.newBuilder() to construct. + private AddressBook(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private AddressBook() { + people_ = java.util.Collections.emptyList(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private AddressBook( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + people_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00000001; + } + people_.add( + input.readMessage(AddressBookProtos.Person.PARSER, extensionRegistry)); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + people_ = java.util.Collections.unmodifiableList(people_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.AddressBook.class, AddressBookProtos.AddressBook.Builder.class); + } + + public static final int PEOPLE_FIELD_NUMBER = 1; + private java.util.List people_; + + /** + * repeated .protobuf.Person people = 1; + */ + public java.util.List getPeopleList() { + return people_; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public java.util.List + getPeopleOrBuilderList() { + return people_; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public int getPeopleCount() { + return people_.size(); + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.Person getPeople(int index) { + return people_.get(index); + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + int index) { + return people_.get(index); + } + + private byte memoizedIsInitialized = -1; + + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + for (int i = 0; i < getPeopleCount(); i++) { + if (!getPeople(i).isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < people_.size(); i++) { + output.writeMessage(1, people_.get(i)); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < people_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, people_.get(i)); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AddressBookProtos.AddressBook)) { + return super.equals(obj); + } + AddressBookProtos.AddressBook other = (AddressBookProtos.AddressBook) obj; + + boolean result = true; + result = result && getPeopleList() + .equals(other.getPeopleList()); + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getPeopleCount() > 0) { + hash = (37 * hash) + PEOPLE_FIELD_NUMBER; + hash = (53 * hash) + getPeopleList().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static AddressBookProtos.AddressBook parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.AddressBook parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.AddressBook parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static AddressBookProtos.AddressBook parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static AddressBookProtos.AddressBook parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.AddressBook parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.AddressBook parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static AddressBookProtos.AddressBook parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static AddressBookProtos.AddressBook parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static AddressBookProtos.AddressBook parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(AddressBookProtos.AddressBook prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code protobuf.AddressBook} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:protobuf.AddressBook) + AddressBookProtos.AddressBookOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable + .ensureFieldAccessorsInitialized( + AddressBookProtos.AddressBook.class, AddressBookProtos.AddressBook.Builder.class); + } + + // Construct using AddressBookProtos.AddressBook.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + getPeopleFieldBuilder(); + } + } + + public Builder clear() { + super.clear(); + if (peopleBuilder_ == null) { + people_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + } else { + peopleBuilder_.clear(); + } + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + } + + public AddressBookProtos.AddressBook getDefaultInstanceForType() { + return AddressBookProtos.AddressBook.getDefaultInstance(); + } + + public AddressBookProtos.AddressBook build() { + AddressBookProtos.AddressBook result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public AddressBookProtos.AddressBook buildPartial() { + AddressBookProtos.AddressBook result = new AddressBookProtos.AddressBook(this); + int from_bitField0_ = bitField0_; + if (peopleBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + people_ = java.util.Collections.unmodifiableList(people_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.people_ = people_; + } else { + result.people_ = peopleBuilder_.build(); + } + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof AddressBookProtos.AddressBook) { + return mergeFrom((AddressBookProtos.AddressBook) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(AddressBookProtos.AddressBook other) { + if (other == AddressBookProtos.AddressBook.getDefaultInstance()) return this; + if (peopleBuilder_ == null) { + if (!other.people_.isEmpty()) { + if (people_.isEmpty()) { + people_ = other.people_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensurePeopleIsMutable(); + people_.addAll(other.people_); + } + onChanged(); + } + } else { + if (!other.people_.isEmpty()) { + if (peopleBuilder_.isEmpty()) { + peopleBuilder_.dispose(); + peopleBuilder_ = null; + people_ = other.people_; + bitField0_ = (bitField0_ & ~0x00000001); + peopleBuilder_ = + com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? + getPeopleFieldBuilder() : null; + } else { + peopleBuilder_.addAllMessages(other.people_); + } + } + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + for (int i = 0; i < getPeopleCount(); i++) { + if (!getPeople(i).isInitialized()) { + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + AddressBookProtos.AddressBook parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (AddressBookProtos.AddressBook) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private java.util.List people_ = + java.util.Collections.emptyList(); + + private void ensurePeopleIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + people_ = new java.util.ArrayList(people_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder> peopleBuilder_; + + /** + * repeated .protobuf.Person people = 1; + */ + public java.util.List getPeopleList() { + if (peopleBuilder_ == null) { + return java.util.Collections.unmodifiableList(people_); + } else { + return peopleBuilder_.getMessageList(); + } + } + + /** + * repeated .protobuf.Person people = 1; + */ + public int getPeopleCount() { + if (peopleBuilder_ == null) { + return people_.size(); + } else { + return peopleBuilder_.getCount(); + } + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.Person getPeople(int index) { + if (peopleBuilder_ == null) { + return people_.get(index); + } else { + return peopleBuilder_.getMessage(index); + } + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder setPeople( + int index, AddressBookProtos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.set(index, value); + onChanged(); + } else { + peopleBuilder_.setMessage(index, value); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder setPeople( + int index, AddressBookProtos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.set(index, builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder addPeople(AddressBookProtos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.add(value); + onChanged(); + } else { + peopleBuilder_.addMessage(value); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder addPeople( + int index, AddressBookProtos.Person value) { + if (peopleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensurePeopleIsMutable(); + people_.add(index, value); + onChanged(); + } else { + peopleBuilder_.addMessage(index, value); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder addPeople( + AddressBookProtos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.add(builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.addMessage(builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder addPeople( + int index, AddressBookProtos.Person.Builder builderForValue) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.add(index, builderForValue.build()); + onChanged(); + } else { + peopleBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder addAllPeople( + java.lang.Iterable values) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, people_); + onChanged(); + } else { + peopleBuilder_.addAllMessages(values); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder clearPeople() { + if (peopleBuilder_ == null) { + people_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + peopleBuilder_.clear(); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public Builder removePeople(int index) { + if (peopleBuilder_ == null) { + ensurePeopleIsMutable(); + people_.remove(index); + onChanged(); + } else { + peopleBuilder_.remove(index); + } + return this; + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.Person.Builder getPeopleBuilder( + int index) { + return getPeopleFieldBuilder().getBuilder(index); + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + int index) { + if (peopleBuilder_ == null) { + return people_.get(index); + } else { + return peopleBuilder_.getMessageOrBuilder(index); + } + } + + /** + * repeated .protobuf.Person people = 1; + */ + public java.util.List + getPeopleOrBuilderList() { + if (peopleBuilder_ != null) { + return peopleBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(people_); + } + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.Person.Builder addPeopleBuilder() { + return getPeopleFieldBuilder().addBuilder( + AddressBookProtos.Person.getDefaultInstance()); + } + + /** + * repeated .protobuf.Person people = 1; + */ + public AddressBookProtos.Person.Builder addPeopleBuilder( + int index) { + return getPeopleFieldBuilder().addBuilder( + index, AddressBookProtos.Person.getDefaultInstance()); + } + + /** + * repeated .protobuf.Person people = 1; + */ + public java.util.List + getPeopleBuilderList() { + return getPeopleFieldBuilder().getBuilderList(); + } + + private com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder> + getPeopleFieldBuilder() { + if (peopleBuilder_ == null) { + peopleBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< + AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder>( + people_, + ((bitField0_ & 0x00000001) == 0x00000001), + getParentForChildren(), + isClean()); + people_ = null; + } + return peopleBuilder_; + } + + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:protobuf.AddressBook) + } + + // @@protoc_insertion_point(class_scope:protobuf.AddressBook) + private static final AddressBookProtos.AddressBook DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new AddressBookProtos.AddressBook(); + } + + public static AddressBookProtos.AddressBook getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated + public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public AddressBook parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new AddressBook(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public AddressBookProtos.AddressBook getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protobuf_Person_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protobuf_Person_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protobuf_Person_PhoneNumber_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_protobuf_AddressBook_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_protobuf_AddressBook_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + + static { + java.lang.String[] descriptorData = { + "\n\020routeguide.proto\022\010protobuf\"\333\001\n\006Person\022" + + "\014\n\004name\030\001 \002(\t\022\n\n\002id\030\002 \002(\005\022\r\n\005email\030\003 \001(\t" + + "\022,\n\006phones\030\004 \003(\0132\034.protobuf.Person.Phone" + + "Number\032M\n\013PhoneNumber\022\016\n\006number\030\001 \002(\t\022.\n" + + "\004type\030\002 \001(\0162\032.protobuf.Person.PhoneType:" + + "\004HOME\"+\n\tPhoneType\022\n\n\006MOBILE\020\000\022\010\n\004HOME\020\001" + + "\022\010\n\004WORK\020\002\"/\n\013AddressBook\022 \n\006people\030\001 \003(" + + "\0132\020.protobuf.PersonB*\n\025com.baeldung.prot" + + "obufB\021AddressBookProtos" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[]{ + }, assigner); + internal_static_protobuf_Person_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_protobuf_Person_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protobuf_Person_descriptor, + new java.lang.String[]{"Name", "Id", "Email", "Phones",}); + internal_static_protobuf_Person_PhoneNumber_descriptor = + internal_static_protobuf_Person_descriptor.getNestedTypes().get(0); + internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protobuf_Person_PhoneNumber_descriptor, + new java.lang.String[]{"Number", "Type",}); + internal_static_protobuf_AddressBook_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_protobuf_AddressBook_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_protobuf_AddressBook_descriptor, + new java.lang.String[]{"People",}); + } + + // @@protoc_insertion_point(outer_class_scope) +} \ No newline at end of file diff --git a/protobuffer/src/main/resources/addressbook.proto b/protobuffer/src/main/resources/addressbook.proto new file mode 100644 index 0000000000..1c0946b7f7 --- /dev/null +++ b/protobuffer/src/main/resources/addressbook.proto @@ -0,0 +1,27 @@ +package protobuf; + +option java_package = "com.baeldung.protobuf"; +option java_outer_classname = "AddressBookProtos"; + +message Person { + required string name = 1; + required int32 id = 2; + optional string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + required string number = 1; + optional PhoneType type = 2 [default = HOME]; + } + + repeated PhoneNumber phones = 4; +} + +message AddressBook { + repeated Person people = 1; +} \ No newline at end of file diff --git a/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java b/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java new file mode 100644 index 0000000000..74447eb4a4 --- /dev/null +++ b/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java @@ -0,0 +1,90 @@ +package com.baeldung.protobuf; + + +import org.junit.After; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Random; + +import static org.junit.Assert.assertEquals; + +public class ProtobufTest { + private final String filePath = "address_book"; + + @After + public void cleanup() throws IOException { + Files.deleteIfExists(Paths.get(filePath)); + } + + @Test + public void givenGeneratedProtobufClass_whenCreateClass_thenShouldCreateJavaInstance() { + //when + String email = "j@baeldung.com"; + int id = new Random().nextInt(); + String name = "Michael Program"; + String number = "01234567890"; + AddressBookProtos.Person.PhoneType type = AddressBookProtos.Person.PhoneType.HOME; + AddressBookProtos.Person person = + AddressBookProtos.Person.newBuilder() + .setId(id) + .setName(name) + .setEmail(email) + .addPhones( + AddressBookProtos.Person.PhoneNumber.newBuilder() + .setNumber(number) + .setType(type)) + .build(); + //then + assertEquals(person.getEmail(), email); + assertEquals(person.getId(), id); + assertEquals(person.getName(), name); + assertEquals(person.getPhones(0).getNumber(), number); + assertEquals(person.getPhones(0).getType(), type); + assertEquals(person.getPhonesList().size(), 1); + } + + + @Test + public void givenAddressBookWithOnePerson_whenSaveAsAFile_shouldLoadFromFileToJavaClass() throws IOException { + //given + String email = "j@baeldung.com"; + int id = new Random().nextInt(); + String name = "Michael Program"; + String number = "01234567890"; + AddressBookProtos.Person.PhoneType type = AddressBookProtos.Person.PhoneType.HOME; + AddressBookProtos.Person person = + AddressBookProtos.Person.newBuilder() + .setId(id) + .setName(name) + .setEmail(email) + .addPhones( + AddressBookProtos.Person.PhoneNumber.newBuilder() + .setNumber(number) + .setType(type)) + .build(); + + //when + AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder().addPeople(person).build(); + FileOutputStream fos = new FileOutputStream(filePath); + addressBook.writeTo(fos); + fos.close(); + + //then + FileInputStream fis = new FileInputStream(filePath); + AddressBookProtos.AddressBook deserialized = + AddressBookProtos.AddressBook.newBuilder().mergeFrom(fis).build(); + fis.close(); + assertEquals(deserialized.getPeople(0).getEmail(), email); + assertEquals(deserialized.getPeople(0).getId(), id); + assertEquals(deserialized.getPeople(0).getName(), name); + assertEquals(deserialized.getPeople(0).getPhones(0).getNumber(), number); + assertEquals(deserialized.getPeople(0).getPhones(0).getType(), type); + assertEquals(deserialized.getPeople(0).getPhonesList().size(), 1); + + } +} From 3de9a69c625c3500f7baa1c259672816aaac4ab3 Mon Sep 17 00:00:00 2001 From: buddhini81 Date: Thu, 9 Mar 2017 21:33:17 +0530 Subject: [PATCH 074/291] Update and rename LoggingFilter.java to LogInFilter.java (#1335) --- .../{LoggingFilter.java => LogInFilter.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename jee7/src/main/java/com/baeldung/javaeeannotations/{LoggingFilter.java => LogInFilter.java} (88%) diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/LoggingFilter.java b/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java similarity index 88% rename from jee7/src/main/java/com/baeldung/javaeeannotations/LoggingFilter.java rename to jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java index 97de5ec0de..9f1345139d 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/LoggingFilter.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java @@ -13,10 +13,10 @@ import javax.servlet.http.HttpServletResponse; @WebFilter( urlPatterns = "/bankAccount/*", - filterName = "LoggingFilter", + filterName = "LogInFilter", description = "Filter all account transaction URLs" ) -public class LoggingFilter implements javax.servlet.Filter { +public class LogInFilter implements javax.servlet.Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } From e46484df4cb62eb35dde15558c42dc093973e29e Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Thu, 9 Mar 2017 19:28:47 +0100 Subject: [PATCH 075/291] FooController refactor (#1345) --- .../org/baeldung/boot/service/FooController.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java b/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java index abd3fccba1..834fa342e2 100644 --- a/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java +++ b/spring-boot/src/main/java/org/baeldung/boot/service/FooController.java @@ -3,8 +3,6 @@ package org.baeldung.boot.service; import org.baeldung.boot.components.FooService; import org.baeldung.boot.model.Foo; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -17,18 +15,12 @@ public class FooController { private FooService fooService; @GetMapping("/{id}") - public ResponseEntity getFooWithId(@PathVariable Integer id) throws Exception { - - Foo foo = fooService.getFooWithId(id); - - return new ResponseEntity<>(foo, HttpStatus.OK); + public Foo getFooWithId(@PathVariable Integer id) throws Exception { + return fooService.getFooWithId(id); } @GetMapping("/") - public ResponseEntity getFooWithName(@RequestParam String name) throws Exception { - - Foo foo = fooService.getFooWithName(name); - - return new ResponseEntity<>(foo, HttpStatus.OK); + public Foo getFooWithName(@RequestParam String name) throws Exception { + return fooService.getFooWithName(name); } } \ No newline at end of file From 64ec368139a7c2d0690095b7cea08e723935d5b0 Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Fri, 10 Mar 2017 02:38:07 +0800 Subject: [PATCH 076/291] #BAEL-505 (#1337) * #BAEL-505 Concurrent Test in Spring 5 * add pom description * add spring-5 module to main pom --- pom.xml | 1 + spring-5/pom.xml | 13 ++++- ...pring5JUnit4ConcurrentIntegrationTest.java | 57 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 spring-5/src/test/java/com/baeldung/Spring5JUnit4ConcurrentIntegrationTest.java diff --git a/pom.xml b/pom.xml index de025d3b4f..edebc30c09 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,7 @@ selenium-junit-testng solr-fulltext-search spark-java + spring-5 spring-akka spring-amqp spring-all diff --git a/spring-5/pom.xml b/spring-5/pom.xml index ab05918ae4..eca36cc1d1 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -9,7 +9,7 @@ jar spring-5 - + spring 5 sample project about new features org.springframework.boot @@ -67,6 +67,17 @@ org.springframework.boot spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + methods + true + + + diff --git a/spring-5/src/test/java/com/baeldung/Spring5JUnit4ConcurrentIntegrationTest.java b/spring-5/src/test/java/com/baeldung/Spring5JUnit4ConcurrentIntegrationTest.java new file mode 100644 index 0000000000..938ee7fd43 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/Spring5JUnit4ConcurrentIntegrationTest.java @@ -0,0 +1,57 @@ +package com.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author aiet + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = Spring5JUnit4ConcurrentIntegrationTest.SimpleConfiguration.class) +public class Spring5JUnit4ConcurrentIntegrationTest implements ApplicationContextAware, InitializingBean { + + @Configuration + public static class SimpleConfiguration { + } + + private ApplicationContext applicationContext; + + private boolean beanInitialized = false; + + @Override + public final void afterPropertiesSet() throws Exception { + this.beanInitialized = true; + } + + @Override + public final void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Test + public final void verifyApplicationContextSet() throws InterruptedException { + TimeUnit.SECONDS.sleep(2); + assertNotNull("The application context should have been set due to ApplicationContextAware semantics.", this.applicationContext); + } + + @Test + public final void verifyBeanInitialized() throws InterruptedException { + TimeUnit.SECONDS.sleep(2); + assertTrue("This test bean should have been initialized due to InitializingBean semantics.", this.beanInitialized); + } + +} + + From 71e0d80096dd3ed5036f9cc00b287d0e8f4cf909 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Thu, 9 Mar 2017 21:03:37 +0100 Subject: [PATCH 077/291] Move @immutable examples to spring-hibernate5 (#1350) --- pom.xml | 1 + .../java/com/baeldung/hibernate/immutable/entities/Event.java | 0 .../com/baeldung/hibernate/immutable/util/HibernateUtil.java | 0 .../hibernate/immutable/HibernateImmutableIntegrationTest.java | 2 ++ 4 files changed, 3 insertions(+) rename {spring-hibernate4 => spring-hibernate5}/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java (100%) rename {spring-hibernate4 => spring-hibernate5}/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java (100%) rename {spring-hibernate4 => spring-hibernate5}/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java (99%) diff --git a/pom.xml b/pom.xml index edebc30c09..193fd8d984 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,7 @@ spring-freemarker spring-hibernate3 spring-hibernate4 + spring-hibernate5 spring-integration spring-jersey spring-jms diff --git a/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java similarity index 100% rename from spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java rename to spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java diff --git a/spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java similarity index 100% rename from spring-hibernate4/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java rename to spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java diff --git a/spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java similarity index 99% rename from spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java rename to spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java index 83a2fd3cb8..1a7aa8cb1d 100644 --- a/spring-hibernate4/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java @@ -11,7 +11,9 @@ import org.junit.Test; import org.junit.rules.ExpectedException; public class HibernateImmutableIntegrationTest { + private Session session; + @Rule public final ExpectedException exception = ExpectedException.none(); From 5840f99d49dc62ece537e3a1bb5332c5390c8fc2 Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Thu, 9 Mar 2017 22:03:53 +0200 Subject: [PATCH 078/291] upgrade to spring boot 1.5.2 (#1346) --- spring-security-openid/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-security-openid/pom.xml b/spring-security-openid/pom.xml index ff0b030bd2..72cc63474b 100644 --- a/spring-security-openid/pom.xml +++ b/spring-security-openid/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 1.4.4.RELEASE + 1.5.2.RELEASE From 453de7e93dc2f5677f9c80630d99ce7f54325624 Mon Sep 17 00:00:00 2001 From: Alex Vargas Date: Thu, 9 Mar 2017 13:56:26 -0800 Subject: [PATCH 079/291] Bael 389 - Setting javax websocket api scope to provided (#1341) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces * BAEL-389 - Building URL dynamically between host and pathname * Setting javax websocket api scope to provided --- java-websocket/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java-websocket/pom.xml b/java-websocket/pom.xml index 929e6491fd..e19706b4d9 100644 --- a/java-websocket/pom.xml +++ b/java-websocket/pom.xml @@ -17,6 +17,7 @@ javax.websocket javax.websocket-api 1.1 + provided com.google.code.gson From 80b222b7bdcc3772db3a0594943abd66c7f9f425 Mon Sep 17 00:00:00 2001 From: Johnson Okorie Date: Fri, 10 Mar 2017 19:41:04 +0100 Subject: [PATCH 080/291] BAEL-482: A Guide to Redis with Redisson (#1353) * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 --- redis/pom.xml | 6 + .../main/java/com/baeldung/CustomMessage.java | 19 ++ redis/src/main/java/com/baeldung/Ledger.java | 21 ++ .../java/com/baeldung/LedgerLiveObject.java | 21 ++ .../java/com/baeldung/LedgerServiceImpl.java | 17 ++ .../com/baeldung/LedgerServiceInterface.java | 10 + .../src/main/resources/singleNodeConfig.json | 27 ++ .../src/main/resources/singleNodeConfig.yaml | 24 ++ .../baeldung/RedissonConfigurationTest.java | 65 +++++ .../test/java/com/baeldung/RedissonTest.java | 237 ++++++++++++++++++ 10 files changed, 447 insertions(+) create mode 100644 redis/src/main/java/com/baeldung/CustomMessage.java create mode 100644 redis/src/main/java/com/baeldung/Ledger.java create mode 100644 redis/src/main/java/com/baeldung/LedgerLiveObject.java create mode 100644 redis/src/main/java/com/baeldung/LedgerServiceImpl.java create mode 100644 redis/src/main/java/com/baeldung/LedgerServiceInterface.java create mode 100644 redis/src/main/resources/singleNodeConfig.json create mode 100644 redis/src/main/resources/singleNodeConfig.yaml create mode 100644 redis/src/test/java/com/baeldung/RedissonConfigurationTest.java create mode 100644 redis/src/test/java/com/baeldung/RedissonTest.java diff --git a/redis/pom.xml b/redis/pom.xml index e3affdd7ef..9025294d59 100644 --- a/redis/pom.xml +++ b/redis/pom.xml @@ -23,6 +23,12 @@ ${embedded-redis.version} + + org.redisson + redisson + 3.3.0 + + junit junit diff --git a/redis/src/main/java/com/baeldung/CustomMessage.java b/redis/src/main/java/com/baeldung/CustomMessage.java new file mode 100644 index 0000000000..1d6a7e4e13 --- /dev/null +++ b/redis/src/main/java/com/baeldung/CustomMessage.java @@ -0,0 +1,19 @@ +package com.baeldung; + +/** + * Created by johnson on 3/9/17. + */ +public class CustomMessage { + private String message; + + public CustomMessage() { + } + + public CustomMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/redis/src/main/java/com/baeldung/Ledger.java b/redis/src/main/java/com/baeldung/Ledger.java new file mode 100644 index 0000000000..da72791f7e --- /dev/null +++ b/redis/src/main/java/com/baeldung/Ledger.java @@ -0,0 +1,21 @@ +package com.baeldung; + +public class Ledger { + + public Ledger() { + } + + public Ledger(String name) { + this.name = name; + } + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/redis/src/main/java/com/baeldung/LedgerLiveObject.java b/redis/src/main/java/com/baeldung/LedgerLiveObject.java new file mode 100644 index 0000000000..395498968e --- /dev/null +++ b/redis/src/main/java/com/baeldung/LedgerLiveObject.java @@ -0,0 +1,21 @@ +package com.baeldung; + +import org.redisson.api.annotation.REntity; +import org.redisson.api.annotation.RId; + +/** + * Created by johnson on 3/9/17. + */ +@REntity +public class LedgerLiveObject { + @RId + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/redis/src/main/java/com/baeldung/LedgerServiceImpl.java b/redis/src/main/java/com/baeldung/LedgerServiceImpl.java new file mode 100644 index 0000000000..207efbcdef --- /dev/null +++ b/redis/src/main/java/com/baeldung/LedgerServiceImpl.java @@ -0,0 +1,17 @@ +package com.baeldung; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by johnson on 3/9/17. + */ +public class LedgerServiceImpl implements LedgerServiceInterface { + + String[] returnArray = {"entry1","entry2","entry3"}; + + @Override + public List getEntries(int count) { + return Arrays.asList(returnArray); + } +} diff --git a/redis/src/main/java/com/baeldung/LedgerServiceInterface.java b/redis/src/main/java/com/baeldung/LedgerServiceInterface.java new file mode 100644 index 0000000000..918623ef7b --- /dev/null +++ b/redis/src/main/java/com/baeldung/LedgerServiceInterface.java @@ -0,0 +1,10 @@ +package com.baeldung; + +import java.util.List; + +/** + * Created by johnson on 3/9/17. + */ +public interface LedgerServiceInterface { + List getEntries(int count); +} diff --git a/redis/src/main/resources/singleNodeConfig.json b/redis/src/main/resources/singleNodeConfig.json new file mode 100644 index 0000000000..f56e13dcfc --- /dev/null +++ b/redis/src/main/resources/singleNodeConfig.json @@ -0,0 +1,27 @@ +{ + "singleServerConfig": { + "idleConnectionTimeout": 10000, + "pingTimeout": 1000, + "connectTimeout": 10000, + "timeout": 3000, + "retryAttempts": 3, + "retryInterval": 1500, + "reconnectionTimeout": 3000, + "failedAttempts": 3, + "password": null, + "subscriptionsPerConnection": 5, + "clientName": null, + "address": "redis://127.0.0.1:6379", + "subscriptionConnectionMinimumIdleSize": 1, + "subscriptionConnectionPoolSize": 50, + "connectionMinimumIdleSize": 10, + "connectionPoolSize": 64, + "database": 0, + "dnsMonitoring": false, + "dnsMonitoringInterval": 5000 + }, + "threads": 0, + "nettyThreads": 0, + "codec": null, + "useLinuxNativeEpoll": false +} \ No newline at end of file diff --git a/redis/src/main/resources/singleNodeConfig.yaml b/redis/src/main/resources/singleNodeConfig.yaml new file mode 100644 index 0000000000..1b05c46be2 --- /dev/null +++ b/redis/src/main/resources/singleNodeConfig.yaml @@ -0,0 +1,24 @@ +singleServerConfig: + idleConnectionTimeout: 10000 + pingTimeout: 1000 + connectTimeout: 10000 + timeout: 3000 + retryAttempts: 3 + retryInterval: 1500 + reconnectionTimeout: 3000 + failedAttempts: 3 + password: null + subscriptionsPerConnection: 5 + clientName: null + address: "redis://127.0.0.1:6379" + subscriptionConnectionMinimumIdleSize: 1 + subscriptionConnectionPoolSize: 50 + connectionMinimumIdleSize: 10 + connectionPoolSize: 64 + database: 0 + dnsMonitoring: false + dnsMonitoringInterval: 5000 +threads: 0 +nettyThreads: 0 +codec: ! {} +useLinuxNativeEpoll: false \ No newline at end of file diff --git a/redis/src/test/java/com/baeldung/RedissonConfigurationTest.java b/redis/src/test/java/com/baeldung/RedissonConfigurationTest.java new file mode 100644 index 0000000000..ba6d2eb54a --- /dev/null +++ b/redis/src/test/java/com/baeldung/RedissonConfigurationTest.java @@ -0,0 +1,65 @@ +package com.baeldung; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import redis.embedded.RedisServer; + +import java.io.File; +import java.io.IOException; + +/** + * Created by johnson on 3/9/17. + */ +public class RedissonConfigurationTest { + private static RedisServer redisServer; + private static RedissonClient client; + + @BeforeClass + public static void setUp() throws IOException { + redisServer = new RedisServer(6379); + redisServer.start(); + } + + @AfterClass + public static void destroy() { + redisServer.stop(); + client.shutdown(); + } + + @Test + public void givenJavaConfig_thenRedissonConnectToRedis() { + Config config = new Config(); + config.useSingleServer() + .setAddress("127.0.0.1:6379"); + + client = Redisson.create(config); + + assert(client != null && client.getKeys().count() >= 0); + } + + @Test + public void givenJSONFileConfig_thenRedissonConnectToRedis() throws IOException { + Config config = Config.fromJSON( + new File(getClass().getClassLoader().getResource( + "singleNodeConfig.json").getFile())); + + client = Redisson.create(config); + + assert(client != null && client.getKeys().count() >= 0); + } + + @Test + public void givenYAMLFileConfig_thenRedissonConnectToRedis() throws IOException { + Config config = Config.fromYAML( + new File(getClass().getClassLoader().getResource( + "singleNodeConfig.yaml").getFile())); + + client = Redisson.create(config); + + assert(client != null && client.getKeys().count() >= 0); + } +} \ No newline at end of file diff --git a/redis/src/test/java/com/baeldung/RedissonTest.java b/redis/src/test/java/com/baeldung/RedissonTest.java new file mode 100644 index 0000000000..59d8a1ebc9 --- /dev/null +++ b/redis/src/test/java/com/baeldung/RedissonTest.java @@ -0,0 +1,237 @@ +package com.baeldung; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.redisson.Redisson; +import org.redisson.RedissonMultiLock; +import org.redisson.api.*; +import org.redisson.api.listener.MessageListener; +import org.redisson.client.RedisClient; +import org.redisson.client.RedisConnection; +import org.redisson.client.codec.StringCodec; +import org.redisson.client.protocol.RedisCommands; +import redis.embedded.RedisServer; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.junit.Assert.assertEquals; + +public class RedissonTest { + + private static RedisServer redisServer; + private static RedissonClient client; + + @BeforeClass + public static void setUp() throws IOException { + redisServer = new RedisServer(6379); + redisServer.start(); + client = Redisson.create(); + } + + @AfterClass + public static void destroy() { + redisServer.stop(); + client.shutdown(); + } + + @Test + public void givenMultipleKeysInRedis_thenGetAllKeys() { + client.getBucket("key1").set("key1"); + client.getBucket("key2").set("key2"); + client.getBucket("key3").set("key3"); + + RKeys keys = client.getKeys(); + + assert(keys.count() >= 3); + } + + @Test + public void givenKeysWithPatternInRedis_thenGetPatternKeys() { + client.getBucket("key1").set("key1"); + client.getBucket("key2").set("key2"); + client.getBucket("key3").set("key3"); + client.getBucket("id4").set("id4"); + + RKeys keys = client.getKeys(); + + Iterable keysWithPattern + = keys.getKeysByPattern("key*"); + + List keyWithPatternList + = StreamSupport.stream( + keysWithPattern.spliterator(), + false).collect(Collectors.toList()); + + assert(keyWithPatternList.size() == 3); + } + + @Test + public void givenAnObject_thenSaveToRedis() { + RBucket bucket = client.getBucket("ledger"); + Ledger ledger = new Ledger(); + ledger.setName("ledger1"); + bucket.set(ledger); + + Ledger returnedLedger = bucket.get(); + + assert( + returnedLedger != null + && returnedLedger.getName().equals("ledger1")); + } + + @Test + public void givenALong_thenSaveLongToRedisAndAtomicallyIncrement(){ + Long value = 5L; + + RAtomicLong atomicLong + = client.getAtomicLong("myAtomicLong"); + atomicLong.set(value); + Long returnValue = atomicLong.incrementAndGet(); + + assert(returnValue == 6L); + } + + @Test + public void givenTopicSubscribedToAChannel_thenReceiveMessageFromChannel() throws ExecutionException, InterruptedException { + CompletableFuture future = new CompletableFuture<>(); + + RTopic subscribeTopic = client.getTopic("baeldung"); + subscribeTopic.addListener(new MessageListener() { + @Override + public void onMessage(String channel, CustomMessage customMessage) { + future.complete(customMessage.getMessage()); + } + }); + + RTopic recieveTopic = client.getTopic("baeldung"); + long clientsReceivedMessage + = recieveTopic.publish(new CustomMessage("This is a message")); + + assertEquals("This is a message", future.get()); + + } + + @Test + public void givenAMap_thenSaveMapToRedis(){ + RMap map = client.getMap("ledger"); + map.put("123", new Ledger("ledger")); + + assert(map.get("123").getName().equals("ledger")); + } + + @Test + public void givenASet_thenSaveSetToRedis(){ + RSet ledgerSet = client.getSet("ledgerSet"); + ledgerSet.add(new Ledger("ledger")); + + assert(ledgerSet.contains(new Ledger("ledger"))); + } + + @Test + public void givenAList_thenSaveListToRedis(){ + RList ledgerList = client.getList("ledgerList"); + ledgerList.add(new Ledger("ledger")); + + assert(ledgerList.contains(new Ledger("ledger"))); + } + + @Test + public void givenLockSet_thenEnsureCanUnlock(){ + RLock lock = client.getLock("lock"); + lock.lock(); + assert(lock.isLocked()); + + lock.unlock(); + assert(!lock.isLocked()); + } + + @Test + public void givenMultipleLocksSet_thenEnsureAllCanUnlock(){ + RedissonClient clientInstance1 = Redisson.create(); + RedissonClient clientInstance2 = Redisson.create(); + RedissonClient clientInstance3 = Redisson.create(); + + RLock lock1 = clientInstance1.getLock("lock1"); + RLock lock2 = clientInstance2.getLock("lock2"); + RLock lock3 = clientInstance3.getLock("lock3"); + + RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3); + lock.lock(); + assert(lock1.isLocked() && lock2.isLocked() && lock3.isLocked()); + + lock.unlock(); + assert(!(lock1.isLocked() || lock2.isLocked() || lock3.isLocked())); + } + + @Test + public void givenRemoteServiceMethodRegistered_thenInvokeMethod(){ + RRemoteService remoteService = client.getRemoteService(); + LedgerServiceImpl ledgerServiceImpl = new LedgerServiceImpl(); + + remoteService.register(LedgerServiceInterface.class, ledgerServiceImpl); + + + LedgerServiceInterface ledgerService + = remoteService.get(LedgerServiceInterface.class); + + List entries = ledgerService.getEntries(10); + + assert(entries.size() == 3 && entries.contains("entry1")); + } + + @Test + public void givenLiveObjectPersisted_thenGetLiveObject(){ + RLiveObjectService service = client.getLiveObjectService(); + + LedgerLiveObject ledger = new LedgerLiveObject(); + ledger.setName("ledger1"); + + ledger = service.persist(ledger); + + LedgerLiveObject returnLedger + = service.get(LedgerLiveObject.class, "ledger1"); + + assert(ledger.getName().equals(returnLedger.getName())); + } + + @Test + public void givenMultipleOperations_thenDoAllAtomically(){ + RBatch batch = client.createBatch(); + batch.getMap("ledgerMap").fastPutAsync("1", "2"); + batch.getMap("ledgerMap").putAsync("2", "5"); + + List result = batch.execute(); + + RMap map = client.getMap("ledgerMap"); + assert(result.size() > 0 && map.get("1").equals("2")); + } + + @Test + public void givenLUAScript_thenExecuteScriptOnRedis(){ + client.getBucket("foo").set("bar"); + String result = client.getScript().eval(RScript.Mode.READ_ONLY, + "return redis.call('get', 'foo')", RScript.ReturnType.VALUE); + + assert(result.equals("bar")); + } + + @Test + public void givenLowLevelRedisCommands_thenExecuteLowLevelCommandsOnRedis(){ + RedisClient client = new RedisClient("localhost", 6379); + RedisConnection conn = client.connect(); + conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0); + + String testValue = conn.sync(StringCodec.INSTANCE, RedisCommands.GET, "test"); + + conn.closeAsync(); + client.shutdown(); + + assert(testValue.equals("0")); + } +} From fb7b2c798c4bcd8183e5bdf4811f43b73021798d Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Fri, 10 Mar 2017 22:30:38 +0100 Subject: [PATCH 081/291] Feature/bael 75 (#1356) * BEAL-75 - Spring Boot Audit Support Source code for http://inprogress.baeldung.com/wp-admin/post.php?post=35337&action=edit * BEAL-75 - Spring Boot Audit Support Update to use SLF4J logger instead of System.out.println * BEAL-75 - Spring Boot Audit Support Give the user the 'ACTUATOR' role so the management endpoints can be viewed when logging on as 'user' --- .../src/main/java/org/baeldung/WebSecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java b/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java index 199edce0bc..9339d8e804 100755 --- a/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java +++ b/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java @@ -29,6 +29,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); + .withUser("user").password("password").roles("USER", "ACTUATOR"); } } From ea26d4209e00fce50669a0ae8cf566a91912b69d Mon Sep 17 00:00:00 2001 From: gitterjim-I Date: Fri, 10 Mar 2017 22:19:26 +0000 Subject: [PATCH 082/291] Bael-667 Flatten Nested Collections (#1330) * article Bael-667 initial commit. * Switch to use logging framework for output. --- core-java/0.8260098203820962 | 0 .../flattennestedlist/FlattenNestedList.java | 17 ++++++ .../FlattenNestedListTest.java | 52 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 core-java/0.8260098203820962 create mode 100644 core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java create mode 100644 core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java diff --git a/core-java/0.8260098203820962 b/core-java/0.8260098203820962 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java b/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java new file mode 100644 index 0000000000..11ee66560b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java @@ -0,0 +1,17 @@ +package com.baeldung.list.flattennestedlist; + +import java.util.ArrayList; +import java.util.List; + +public class FlattenNestedList { + + public List flattenListOfLists(List> lol) { + + // flatten the list + List ls = new ArrayList<>(); + lol.forEach((k) -> ls.addAll(k)); + + return ls; + } + +} diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java new file mode 100644 index 0000000000..09bfdae9a5 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -0,0 +1,52 @@ +package com.baeldung.list.flattennestedlist; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FlattenNestedListTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(FlattenNestedListTest.class); + private FlattenNestedList flol; + + @Before + public void setup() { + flol = new FlattenNestedList(); + } + + @Test + public void givenListOfListOfString_flattenNestedList() { + + // create the list to flatten + List ls1 = Arrays.asList("one:one", "one:two", "one:three"); + List ls2 = Arrays.asList("two:one", "two:two", "two:three"); + List ls3 = Arrays.asList("three:one", "three:two", "three:three"); + + List> lol = new ArrayList<>(); + lol.addAll(Arrays.asList(ls1, ls2, ls3)); + + // show nested list + LOGGER.debug("\nNested list: "); + lol.forEach((nl) -> LOGGER.debug(nl + "")); + + // flatten it + List ls = flol.flattenListOfLists(lol); + + assertNotNull(ls); + assertTrue(ls.size() == 9); + + // show flattened list + LOGGER.debug("\nFlattened list:"); + ls.forEach((l) -> LOGGER.debug(l)); + + } + +} From 805868f75ffa81ddce1c486d233d6032051e45a5 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 10 Mar 2017 23:42:45 +0100 Subject: [PATCH 083/291] Refactor LDAPClient (#1357) --- .../com/baeldung/ldap/client/LdapClient.java | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java index 8c71007b27..0c77d0f87d 100644 --- a/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java +++ b/spring-ldap/src/main/java/com/baeldung/ldap/client/LdapClient.java @@ -1,23 +1,16 @@ package com.baeldung.ldap.client; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.ldap.core.*; +import org.springframework.ldap.support.LdapNameBuilder; + +import javax.naming.Name; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.List; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.ldap.core.AttributesMapper; -import org.springframework.ldap.core.ContextSource; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.support.LdapNameBuilder; - public class LdapClient { @Autowired @@ -34,16 +27,20 @@ public class LdapClient { } public List search(final String username) { - List users = ldapTemplate.search("ou=users", "cn=" + username, new AttributesMapper() { - public String mapFromAttributes(Attributes attrs) throws NamingException { - return (String) attrs.get("cn").get(); - } - }); - return users; + return ldapTemplate.search( + "ou=users", + "cn=" + username, + (AttributesMapper) attrs -> (String) attrs + .get("cn") + .get()); } public void create(final String username, final String password) { - Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build(); + Name dn = LdapNameBuilder + .newInstance() + .add("ou", "users") + .add("cn", username) + .build(); DirContextAdapter context = new DirContextAdapter(dn); context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" }); @@ -55,7 +52,11 @@ public class LdapClient { } public void modify(final String username, final String password) { - Name dn = LdapNameBuilder.newInstance().add("ou", "users").add("cn", username).build(); + Name dn = LdapNameBuilder + .newInstance() + .add("ou", "users") + .add("cn", username) + .build(); DirContextOperations context = ldapTemplate.lookupContext(dn); context.setAttributeValues("objectclass", new String[] { "top", "person", "organizationalPerson", "inetOrgPerson" }); @@ -71,7 +72,9 @@ public class LdapClient { try { MessageDigest digest = MessageDigest.getInstance("SHA"); digest.update(password.getBytes()); - base64 = Base64.getEncoder().encodeToString(digest.digest()); + base64 = Base64 + .getEncoder() + .encodeToString(digest.digest()); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } From 0647c31521e196332fa491b0a1089cfbb524dca3 Mon Sep 17 00:00:00 2001 From: lor6 Date: Sat, 11 Mar 2017 04:45:19 +0200 Subject: [PATCH 084/291] multiple http elems config, controller, pages, test (#1307) * multiple http elems config, controller, pages, test * fix dependencies * formatting * formatting * update security-test versiob --- spring-security-mvc-boot/pom.xml | 66 ++++++++++++++-- .../main/java/org/baeldung/Application.java | 3 +- .../MultipleEntryPointsApplication.java | 12 +++ .../MultipleEntryPointsSecurityConfig.java | 79 +++++++++++++++++++ .../multipleentrypoints/PagesController.java | 38 +++++++++ .../spring-security-multiple-entry.xml | 37 +++++++++ .../templates/multipleHttpElems/login.html | 27 +++++++ .../multipleHttpElems/multipleHttpLinks.html | 16 ++++ .../multipleHttpElems/myAdminPage.html | 13 +++ .../multipleHttpElems/myGuestPage.html | 13 +++ .../multipleHttpElems/myUserPage.html | 13 +++ .../baeldung/web/MultipleEntryPointsTest.java | 64 +++++++++++++++ 12 files changed, 374 insertions(+), 7 deletions(-) create mode 100644 spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsApplication.java create mode 100644 spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java create mode 100644 spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java create mode 100644 spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/login.html create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myAdminPage.html create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myGuestPage.html create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myUserPage.html create mode 100644 spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java diff --git a/spring-security-mvc-boot/pom.xml b/spring-security-mvc-boot/pom.xml index 591ededccf..16535b09a7 100644 --- a/spring-security-mvc-boot/pom.xml +++ b/spring-security-mvc-boot/pom.xml @@ -18,15 +18,20 @@ + org.springframework.boot spring-boot-starter-security - + org.springframework.boot spring-boot-starter-web - + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + org.springframework.boot spring-boot-starter-tomcat @@ -54,13 +59,13 @@ com.h2database h2 - + org.springframework.boot spring-boot-starter-test test - + junit junit @@ -97,6 +102,12 @@ spring-test test + + + org.springframework.security + spring-security-test + test + org.apache.derby @@ -140,7 +151,7 @@ jstl-api ${jstl.version} - + @@ -158,6 +169,7 @@ **/*IntegrationTest.java **/*LiveTest.java + **/*EntryPointsTest.java @@ -279,6 +291,43 @@ + + + entryPoints + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + **/*IntegrationTest.java + + + **/*EntryPointsTest.java + + + + + + + json + + + + + + + @@ -288,12 +337,17 @@ + + + UTF-8 1.8 10.13.1.1 1.1.2 4.2.0.RELEASE - 4.2.0.RELEASE + 4.2.0.RELEASE + 4.2.0.RELEASE + 8.5.11 1.2 2.4.0 diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java index 03de5897f5..ae2651c06f 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java @@ -9,7 +9,8 @@ import org.springframework.context.annotation.FilterType; @Configuration @EnableAutoConfiguration -@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.voter.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multiplelogin.*") }) +@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.voter.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multiplelogin.*"), + @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleentrypoints.*") }) public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsApplication.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsApplication.java new file mode 100644 index 0000000000..4e5fafcd99 --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsApplication.java @@ -0,0 +1,12 @@ +package org.baeldung.multipleentrypoints; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +// @ImportResource({"classpath*:spring-security-multiple-entry.xml"}) +public class MultipleEntryPointsApplication { + public static void main(String[] args) { + SpringApplication.run(MultipleEntryPointsApplication.class, args); + } +} diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java new file mode 100644 index 0000000000..9da2ef20e3 --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java @@ -0,0 +1,79 @@ +package org.baeldung.multipleentrypoints; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +@Configuration +@EnableWebSecurity +public class MultipleEntryPointsSecurityConfig { + + @Bean + public UserDetailsService userDetailsService() throws Exception { + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); + manager.createUser(User.withUsername("user").password("userPass").roles("USER").build()); + manager.createUser(User.withUsername("admin").password("adminPass").roles("ADMIN").build()); + return manager; + } + + @Configuration + @Order(1) + public static class App1ConfigurationAdapter extends WebSecurityConfigurerAdapter { + + public App1ConfigurationAdapter() { + super(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + //@formatter:off + http.antMatcher("/admin/**") + .authorizeRequests().anyRequest().hasRole("ADMIN") + .and().httpBasic() + .and().exceptionHandling().accessDeniedPage("/403"); + //@formatter:on + } + } + + @Configuration + @Order(2) + public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter { + + public App2ConfigurationAdapter() { + super(); + } + + protected void configure(HttpSecurity http) throws Exception { + //@formatter:off + http.antMatcher("/user/**") + .authorizeRequests().anyRequest().hasRole("USER") + .and().formLogin().loginPage("/userLogin").loginProcessingUrl("/user/login") + .failureUrl("/userLogin?error=loginError").defaultSuccessUrl("/user/myUserPage") + .and().logout().logoutUrl("/user/logout").logoutSuccessUrl("/multipleHttpLinks") + .deleteCookies("JSESSIONID") + .and().exceptionHandling().accessDeniedPage("/403") + .and().csrf().disable(); + //@formatter:on + } + } + + @Configuration + @Order(3) + public static class App3ConfigurationAdapter extends WebSecurityConfigurerAdapter { + + public App3ConfigurationAdapter() { + super(); + } + + protected void configure(HttpSecurity http) throws Exception { + http.antMatcher("/guest/**").authorizeRequests().anyRequest().permitAll(); + } + } + +} diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java new file mode 100644 index 0000000000..3b59678b87 --- /dev/null +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java @@ -0,0 +1,38 @@ +package org.baeldung.multipleentrypoints; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class PagesController { + + @RequestMapping("/multipleHttpLinks") + public String getMultipleHttpLinksPage() { + return "multipleHttpElems/multipleHttpLinks"; + } + + @RequestMapping("/admin/myAdminPage") + public String getAdminPage() { + return "multipleHttpElems/myAdminPage"; + } + + @RequestMapping("/user/myUserPage") + public String getUserPage() { + return "multipleHttpElems/myUserPage"; + } + + @RequestMapping("/guest/myGuestPage") + public String getGuestPage() { + return "multipleHttpElems/myGuestPage"; + } + + @RequestMapping("/userLogin") + public String getUserLoginPage() { + return "multipleHttpElems/login"; + } + + @RequestMapping("/403") + public String getAccessDeniedPage() { + return "403"; + } +} diff --git a/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml new file mode 100644 index 0000000000..1a68bd5c30 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/login.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/login.html new file mode 100644 index 0000000000..2119baec66 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/login.html @@ -0,0 +1,27 @@ + + + + +

Login

+ +
+ + + + + + + + + + + + + + +
Username:
Password:
+ +
+ + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html new file mode 100644 index 0000000000..4a2af1d649 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html @@ -0,0 +1,16 @@ + + + + +Multiple Http Elements Links + + + +Admin page +
+User page +
+Guest page + + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myAdminPage.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myAdminPage.html new file mode 100644 index 0000000000..3003833562 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myAdminPage.html @@ -0,0 +1,13 @@ + + + + +Admin Page + + +Welcome admin! + +

+Back to links + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myGuestPage.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myGuestPage.html new file mode 100644 index 0000000000..47a4c9c44a --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myGuestPage.html @@ -0,0 +1,13 @@ + + + + +Guest Page + + +Welcome guest! + +

+Back to links + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myUserPage.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myUserPage.html new file mode 100644 index 0000000000..f6c2def0b8 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myUserPage.html @@ -0,0 +1,13 @@ + + + + +User Page + + +Welcome user! Logout + +

+Back to links + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java new file mode 100644 index 0000000000..96d38d4943 --- /dev/null +++ b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java @@ -0,0 +1,64 @@ +package org.baeldung.web; + +import org.baeldung.multipleentrypoints.MultipleEntryPointsApplication; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.web.FilterChainProxy; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; + +@RunWith(SpringRunner.class) +@WebAppConfiguration +@SpringBootTest(classes = MultipleEntryPointsApplication.class) +public class MultipleEntryPointsTest { + @Autowired + private WebApplicationContext wac; + + @Autowired + private FilterChainProxy springSecurityFilterChain; + + private MockMvc mockMvc; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilter(springSecurityFilterChain).build(); + } + + @Test + public void whenTestAdminCredentials_thenOk() throws Exception { + mockMvc.perform(get("/admin/myAdminPage")).andExpect(status().isUnauthorized()); + + mockMvc.perform(get("/admin/myAdminPage").with(httpBasic("admin", "adminPass"))).andExpect(status().isOk()); + + mockMvc.perform(get("/user/myUserPage").with(user("admin").password("adminPass").roles("ADMIN"))).andExpect(status().isForbidden()); + + } + + @Test + public void whenTestUserCredentials_thenOk() throws Exception { + mockMvc.perform(get("/user/myUserPage")).andExpect(status().isFound()); + + mockMvc.perform(get("/user/myUserPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isOk()); + + mockMvc.perform(get("/admin/myAdminPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isForbidden()); + } + + @Test + public void givenAnyUser_whenGetGuestPage_thenOk() throws Exception { + mockMvc.perform(get("/guest/myGuestPage")).andExpect(status().isOk()); + + mockMvc.perform(get("/guest/myGuestPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isOk()); + + mockMvc.perform(get("/guest/myGuestPage").with(httpBasic("admin", "adminPass"))).andExpect(status().isOk()); + } +} From e0d59494c124a85c1045a6d5b6b3beafd0243192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20G=C3=B3mez?= Date: Sat, 11 Mar 2017 00:36:38 -0600 Subject: [PATCH 085/291] Lombok annotation update (#1358) * Add project for hibernate immutable article Add Event entity Add hibernate configuration file Add hibernateutil for configuration Add test to match snippets from article * Update Lombok annotations Change annotations to @RequiredArgsConstructor for - ApologizeService - ThankingService * Remove hibernate-immutable due to conflic on PR --- .../src/main/java/com/baeldung/lombok/ApologizeService.java | 4 ++-- .../src/main/java/com/baeldung/lombok/ThankingService.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-core/src/main/java/com/baeldung/lombok/ApologizeService.java b/spring-core/src/main/java/com/baeldung/lombok/ApologizeService.java index 25ef65cad2..76c3df8217 100644 --- a/spring-core/src/main/java/com/baeldung/lombok/ApologizeService.java +++ b/spring-core/src/main/java/com/baeldung/lombok/ApologizeService.java @@ -1,11 +1,11 @@ package com.baeldung.lombok; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -@AllArgsConstructor +@RequiredArgsConstructor public class ApologizeService { private final Translator translator; diff --git a/spring-core/src/main/java/com/baeldung/lombok/ThankingService.java b/spring-core/src/main/java/com/baeldung/lombok/ThankingService.java index f3bdf8bb7f..2e0c398d2d 100644 --- a/spring-core/src/main/java/com/baeldung/lombok/ThankingService.java +++ b/spring-core/src/main/java/com/baeldung/lombok/ThankingService.java @@ -1,10 +1,10 @@ package com.baeldung.lombok; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component -@AllArgsConstructor +@RequiredArgsConstructor public class ThankingService { private final Translator translator; From ffb24cf31209f58d1e6f65f7f98a98913bbb316c Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 11 Mar 2017 14:37:28 +0100 Subject: [PATCH 086/291] Refactor Hibernate5 examples (#1362) --- spring-hibernate5/pom.xml | 1 - .../immutable/util/HibernateUtil.java | 6 ++-- .../src/main/resources/immutable.cfg.xml | 32 +++++++++++++++++ .../HibernateImmutableIntegrationTest.java | 35 +++++++++++-------- 4 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 spring-hibernate5/src/main/resources/immutable.cfg.xml diff --git a/spring-hibernate5/pom.xml b/spring-hibernate5/pom.xml index 81f8084d74..752cbdba1d 100644 --- a/spring-hibernate5/pom.xml +++ b/spring-hibernate5/pom.xml @@ -148,7 +148,6 @@ org.hsqldb hsqldb ${hsqldb.version} - test
diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java index 0918ff105a..4ad7c32450 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java +++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java @@ -1,5 +1,6 @@ package com.baeldung.hibernate.immutable.util; +import com.baeldung.hibernate.immutable.entities.Event; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; @@ -12,10 +13,11 @@ public class HibernateUtil { try { // Create a session factory from immutable.cfg.xml Configuration configuration = new Configuration(); + configuration.addAnnotatedClass(Event.class); configuration.configure("immutable.cfg.xml"); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() - .applySettings(configuration.getProperties()) - .build(); + .applySettings(configuration.getProperties()) + .build(); return configuration.buildSessionFactory(serviceRegistry); } catch (Throwable ex) { System.out.println("Initial SessionFactory creation failed." + ex); diff --git a/spring-hibernate5/src/main/resources/immutable.cfg.xml b/spring-hibernate5/src/main/resources/immutable.cfg.xml new file mode 100644 index 0000000000..a572ebeac2 --- /dev/null +++ b/spring-hibernate5/src/main/resources/immutable.cfg.xml @@ -0,0 +1,32 @@ + + + + + + + + + org.hsqldb.jdbcDriver + jdbc:hsqldb:mem:test + sa + + + + 1 + + + org.hibernate.dialect.HSQLDialect + + + thread + + + true + + + update + + + \ No newline at end of file diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java index 1a7aa8cb1d..fb7653d9f4 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java @@ -2,30 +2,36 @@ package com.baeldung.hibernate.immutable; import com.baeldung.hibernate.immutable.entities.Event; import com.baeldung.hibernate.immutable.util.HibernateUtil; -import org.hibernate.HibernateException; +import com.google.common.collect.Sets; +import org.hibernate.CacheMode; import org.hibernate.Session; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.rules.ExpectedException; +import javax.persistence.PersistenceException; + public class HibernateImmutableIntegrationTest { - private Session session; + private static Session session; @Rule public final ExpectedException exception = ExpectedException.none(); @Before - public void setup() { + public void before() { session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); createEvent(); + session.setCacheMode(CacheMode.REFRESH); } - @After - public void teardown() { + @BeforeClass + public static void setup() { + session = HibernateUtil.getSessionFactory().getCurrentSession(); + } + + @AfterClass + public static void teardown() { HibernateUtil.getSessionFactory().close(); } @@ -40,7 +46,7 @@ public class HibernateImmutableIntegrationTest { @Test public void updateEvent() { Event event = (Event) session.createQuery( - "FROM Event WHERE title='My Event'").list().get(0); + "FROM Event WHERE title='New Event'").list().get(0); event.setTitle("Private Event"); session.saveOrUpdate(event); session.getTransaction().commit(); @@ -49,7 +55,7 @@ public class HibernateImmutableIntegrationTest { @Test public void deleteEvent() { Event event = (Event) session.createQuery( - "FROM Event WHERE title='My Event'").list().get(0); + "FROM Event WHERE title='New Event'").list().get(0); session.delete(event); session.getTransaction().commit(); } @@ -61,7 +67,7 @@ public class HibernateImmutableIntegrationTest { String newGuest = "Sara"; event.getGuestList().add(newGuest); - exception.expect(HibernateException.class); + exception.expect(PersistenceException.class); session.save(event); session.getTransaction().commit(); } @@ -73,14 +79,15 @@ public class HibernateImmutableIntegrationTest { String guest = event.getGuestList().iterator().next(); event.getGuestList().remove(guest); - exception.expect(HibernateException.class); + exception.expect(PersistenceException.class); session.saveOrUpdate(event); session.getTransaction().commit(); } - public void createEvent() { + public static void createEvent() { Event event = new Event(); event.setTitle("New Event"); + event.setGuestList(Sets.newHashSet("guest")); session.save(event); } } From 86eb549596add0784d6b86d1064ac3c139219de2 Mon Sep 17 00:00:00 2001 From: eugenp Date: Sat, 11 Mar 2017 21:53:39 +0200 Subject: [PATCH 087/291] minor cleanup work --- .../criteria/view/ApplicationView.java | 9 ++--- .../hibernate/immutable/entities/Event.java | 2 +- .../immutable/util/HibernateUtil.java | 4 +-- .../AbstractHibernateAuditableService.java | 3 +- .../common/AbstractHibernateService.java | 3 +- .../HibernateCriteriaIntegrationTest.java | 33 +++++++------------ .../criteria/HibernateCriteriaTestRunner.java | 2 +- .../HibernateImmutableIntegrationTest.java | 12 +++---- ...oPaginationPersistenceIntegrationTest.java | 15 +++------ .../FooSortingPersistenceIntegrationTest.java | 4 +-- .../persistence/save/SaveMethodsTest.java | 19 ++++------- .../FooStoredProceduresIntegrationTest.java | 6 ++-- 12 files changed, 37 insertions(+), 75 deletions(-) diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/criteria/view/ApplicationView.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/criteria/view/ApplicationView.java index a854b51753..7b53a5f752 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/hibernate/criteria/view/ApplicationView.java +++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/criteria/view/ApplicationView.java @@ -27,11 +27,7 @@ import com.baeldung.hibernate.criteria.model.Item; import com.baeldung.hibernate.criteria.util.HibernateUtil; public class ApplicationView { - - public ApplicationView() { - - } - + @SuppressWarnings("unchecked") public boolean checkIfCriteriaTimeLower() { final Session session = HibernateUtil.getHibernateSession(); @@ -181,8 +177,7 @@ public class ApplicationView { CriteriaBuilder builder = session.getCriteriaBuilder(); CriteriaQuery criteriaItem = builder.createQuery(Item.class); Root rootItem = criteriaItem.from(Item.class); - criteriaItem.select(rootItem).where(builder.isNull(rootItem.get("itemDescription"))) - .where(builder.like(rootItem.get("itemName"), "chair%")); + criteriaItem.select(rootItem).where(builder.isNull(rootItem.get("itemDescription"))).where(builder.like(rootItem.get("itemName"), "chair%")); final List notNullItemsList = session.createQuery(criteriaItem).getResultList(); final String notNullDescItems[] = new String[notNullItemsList.size()]; for (int i = 0; i < notNullItemsList.size(); i++) { diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java index 69cedd39d3..2928ffe981 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java +++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/entities/Event.java @@ -47,7 +47,7 @@ public class Event { this.title = title; } - @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) + @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.DELETE }) public Set getGuestList() { return guestList; } diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java index 4ad7c32450..e4a2319c37 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java +++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/immutable/util/HibernateUtil.java @@ -15,9 +15,7 @@ public class HibernateUtil { Configuration configuration = new Configuration(); configuration.addAnnotatedClass(Event.class); configuration.configure("immutable.cfg.xml"); - ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() - .applySettings(configuration.getProperties()) - .build(); + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); return configuration.buildSessionFactory(serviceRegistry); } catch (Throwable ex) { System.out.println("Initial SessionFactory creation failed." + ex); diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateAuditableService.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateAuditableService.java index 8e2df15519..2695d7760a 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateAuditableService.java +++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateAuditableService.java @@ -8,8 +8,7 @@ import com.baeldung.persistence.dao.common.IOperations; import org.springframework.transaction.annotation.Transactional; @Transactional(value = "hibernateTransactionManager") -public abstract class AbstractHibernateAuditableService extends AbstractHibernateService - implements IOperations, IAuditOperations { +public abstract class AbstractHibernateAuditableService extends AbstractHibernateService implements IOperations, IAuditOperations { @Override public List getEntitiesAtRevision(final Number revision) { diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateService.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateService.java index 5da2f299f1..02b8ccf48b 100644 --- a/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateService.java +++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/service/common/AbstractHibernateService.java @@ -7,8 +7,7 @@ import com.baeldung.persistence.dao.common.IOperations; import org.springframework.transaction.annotation.Transactional; @Transactional(value = "hibernateTransactionManager") -public abstract class AbstractHibernateService extends AbstractService implements - IOperations { +public abstract class AbstractHibernateService extends AbstractService implements IOperations { @Override public T findOne(final long id) { diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaIntegrationTest.java index 7caa02f156..c7d59e3b00 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaIntegrationTest.java @@ -24,8 +24,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testLikeCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedLikeList = session.createQuery("From Item where itemName like '%chair%'") - .getResultList(); + final List expectedLikeList = session.createQuery("From Item where itemName like '%chair%'").getResultList(); final String expectedLikeItems[] = new String[expectedLikeList.size()]; for (int i = 0; i < expectedLikeList.size(); i++) { expectedLikeItems[i] = expectedLikeList.get(i).getItemName(); @@ -37,8 +36,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testILikeCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedChairCaseList = session.createQuery("From Item where itemName like '%Chair%'") - .getResultList(); + final List expectedChairCaseList = session.createQuery("From Item where itemName like '%Chair%'").getResultList(); final String expectedChairCaseItems[] = new String[expectedChairCaseList.size()]; for (int i = 0; i < expectedChairCaseList.size(); i++) { expectedChairCaseItems[i] = expectedChairCaseList.get(i).getItemName(); @@ -51,8 +49,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testNullCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedIsNullDescItemsList = session.createQuery("From Item where itemDescription is null") - .getResultList(); + final List expectedIsNullDescItemsList = session.createQuery("From Item where itemDescription is null").getResultList(); final String expectedIsNullDescItems[] = new String[expectedIsNullDescItemsList.size()]; for (int i = 0; i < expectedIsNullDescItemsList.size(); i++) { expectedIsNullDescItems[i] = expectedIsNullDescItemsList.get(i).getItemName(); @@ -64,8 +61,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testIsNotNullCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedIsNotNullDescItemsList = session.createQuery( - "From Item where itemDescription is not null").getResultList(); + final List expectedIsNotNullDescItemsList = session.createQuery("From Item where itemDescription is not null").getResultList(); final String expectedIsNotNullDescItems[] = new String[expectedIsNotNullDescItemsList.size()]; for (int i = 0; i < expectedIsNotNullDescItemsList.size(); i++) { expectedIsNotNullDescItems[i] = expectedIsNotNullDescItemsList.get(i).getItemName(); @@ -78,8 +74,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testAverageProjection() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedAvgProjItemsList = session.createQuery("Select avg(itemPrice) from Item item") - .getResultList(); + final List expectedAvgProjItemsList = session.createQuery("Select avg(itemPrice) from Item item").getResultList(); final Double expectedAvgProjItems[] = new Double[expectedAvgProjItemsList.size()]; for (int i = 0; i < expectedAvgProjItemsList.size(); i++) { @@ -105,8 +100,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testOrCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedOrCritItemsList = session.createQuery( - "From Item where itemPrice>1000 or itemName like 'Chair%'").getResultList(); + final List expectedOrCritItemsList = session.createQuery("From Item where itemPrice>1000 or itemName like 'Chair%'").getResultList(); final String expectedOrCritItems[] = new String[expectedOrCritItemsList.size()]; for (int i = 0; i < expectedOrCritItemsList.size(); i++) { expectedOrCritItems[i] = expectedOrCritItemsList.get(i).getItemName(); @@ -118,8 +112,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testAndCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedAndCritItemsList = session.createQuery( - "From Item where itemPrice>1000 and itemName like 'Chair%'").getResultList(); + final List expectedAndCritItemsList = session.createQuery("From Item where itemPrice>1000 and itemName like 'Chair%'").getResultList(); final String expectedAndCritItems[] = new String[expectedAndCritItemsList.size()]; for (int i = 0; i < expectedAndCritItemsList.size(); i++) { expectedAndCritItems[i] = expectedAndCritItemsList.get(i).getItemName(); @@ -131,8 +124,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testMultiCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedMultiCritItemsList = session.createQuery( - "From Item where itemDescription is null and itemName like'chair%'").getResultList(); + final List expectedMultiCritItemsList = session.createQuery("From Item where itemDescription is null and itemName like'chair%'").getResultList(); final String expectedMultiCritItems[] = new String[expectedMultiCritItemsList.size()]; for (int i = 0; i < expectedMultiCritItemsList.size(); i++) { expectedMultiCritItems[i] = expectedMultiCritItemsList.get(i).getItemName(); @@ -144,8 +136,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testSortCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedSortCritItemsList = session.createQuery( - "From Item order by itemName asc, itemPrice desc").getResultList(); + final List expectedSortCritItemsList = session.createQuery("From Item order by itemName asc, itemPrice desc").getResultList(); final String expectedSortCritItems[] = new String[expectedSortCritItemsList.size()]; for (int i = 0; i < expectedSortCritItemsList.size(); i++) { expectedSortCritItems[i] = expectedSortCritItemsList.get(i).getItemName(); @@ -157,8 +148,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void testGreaterThanCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedGreaterThanList = session.createQuery("From Item where itemPrice>1000") - .getResultList(); + final List expectedGreaterThanList = session.createQuery("From Item where itemPrice>1000").getResultList(); final String expectedGreaterThanItems[] = new String[expectedGreaterThanList.size()]; for (int i = 0; i < expectedGreaterThanList.size(); i++) { expectedGreaterThanItems[i] = expectedGreaterThanList.get(i).getItemName(); @@ -182,8 +172,7 @@ public class HibernateCriteriaIntegrationTest { @Test public void betweenCriteriaQuery() { final Session session = HibernateUtil.getHibernateSession(); - final List expectedBetweenList = session.createQuery("From Item where itemPrice between 100 and 200") - .getResultList(); + final List expectedBetweenList = session.createQuery("From Item where itemPrice between 100 and 200").getResultList(); final String expectedPriceBetweenItems[] = new String[expectedBetweenList.size()]; for (int i = 0; i < expectedBetweenList.size(); i++) { expectedPriceBetweenItems[i] = expectedBetweenList.get(i).getItemName(); diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java index 99164efb7a..3228f917fd 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java +++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java @@ -9,7 +9,7 @@ public class HibernateCriteriaTestRunner { public static void main(final String[] args) { Result result = JUnitCore.runClasses(HibernateCriteriaTestSuite.class); for (Failure failure : result.getFailures()) { - + // } } } diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java index fb7653d9f4..801ddcdb45 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/immutable/HibernateImmutableIntegrationTest.java @@ -45,8 +45,7 @@ public class HibernateImmutableIntegrationTest { @Test public void updateEvent() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='New Event'").list().get(0); + Event event = (Event) session.createQuery("FROM Event WHERE title='New Event'").list().get(0); event.setTitle("Private Event"); session.saveOrUpdate(event); session.getTransaction().commit(); @@ -54,16 +53,14 @@ public class HibernateImmutableIntegrationTest { @Test public void deleteEvent() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='New Event'").list().get(0); + Event event = (Event) session.createQuery("FROM Event WHERE title='New Event'").list().get(0); session.delete(event); session.getTransaction().commit(); } @Test public void addGuest() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='New Event'").list().get(0); + Event event = (Event) session.createQuery("FROM Event WHERE title='New Event'").list().get(0); String newGuest = "Sara"; event.getGuestList().add(newGuest); @@ -74,8 +71,7 @@ public class HibernateImmutableIntegrationTest { @Test public void deleteCascade() { - Event event = (Event) session.createQuery( - "FROM Event WHERE title='New Event'").list().get(0); + Event event = (Event) session.createQuery("FROM Event WHERE title='New Event'").list().get(0); String guest = event.getGuestList().iterator().next(); event.getGuestList().remove(guest); diff --git a/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java index c9152b4d85..e6548ce5e7 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooPaginationPersistenceIntegrationTest.java @@ -73,8 +73,7 @@ public class FooPaginationPersistenceIntegrationTest { public final void whenRetrievingPaginatedEntities_thenCorrectSize() { final int pageNumber = 1; final int pageSize = 10; - final List fooList = session.createQuery("From Foo").setFirstResult((pageNumber - 1) * pageSize) - .setMaxResults(pageSize).getResultList(); + final List fooList = session.createQuery("From Foo").setFirstResult((pageNumber - 1) * pageSize).setMaxResults(pageSize).getResultList(); assertThat(fooList, hasSize(pageSize)); } @@ -90,8 +89,7 @@ public class FooPaginationPersistenceIntegrationTest { final List fooList = Lists.newArrayList(); int totalEntities = 0; while (totalEntities < countResult) { - fooList.addAll(session.createQuery("From Foo").setFirstResult((pageNumber - 1) * pageSize) - .setMaxResults(pageSize).getResultList()); + fooList.addAll(session.createQuery("From Foo").setFirstResult((pageNumber - 1) * pageSize).setMaxResults(pageSize).getResultList()); totalEntities = fooList.size(); pageNumber++; } @@ -106,8 +104,7 @@ public class FooPaginationPersistenceIntegrationTest { final Long countResults = (Long) session.createQuery(countQ).uniqueResult(); final int lastPageNumber = (int) ((countResults / pageSize) + 1); - final List lastPage = session.createQuery("From Foo").setFirstResult((lastPageNumber - 1) * pageSize) - .setMaxResults(pageSize).getResultList(); + final List lastPage = session.createQuery("From Foo").setFirstResult((lastPageNumber - 1) * pageSize).setMaxResults(pageSize).getResultList(); assertThat(lastPage, hasSize(lessThan(pageSize + 1))); } @@ -147,8 +144,7 @@ public class FooPaginationPersistenceIntegrationTest { CriteriaQuery criteriaItem = builder.createQuery(Foo.class); Root rootItem = criteriaItem.from(Foo.class); criteriaItem.select(rootItem); - final List firstPage = session.createQuery(criteriaItem).setFirstResult(0).setMaxResults(pageSize) - .getResultList(); + final List firstPage = session.createQuery(criteriaItem).setFirstResult(0).setMaxResults(pageSize).getResultList(); assertThat(firstPage, hasSize(pageSize)); } @@ -175,8 +171,7 @@ public class FooPaginationPersistenceIntegrationTest { int totalEntities = 0; while (totalEntities < count.intValue()) { - fooList.addAll(session.createQuery(criteriaFoo).setFirstResult((pageNumber - 1) * pageSize) - .setMaxResults(pageSize).getResultList()); + fooList.addAll(session.createQuery(criteriaFoo).setFirstResult((pageNumber - 1) * pageSize).setMaxResults(pageSize).getResultList()); totalEntities = fooList.size(); pageNumber++; } diff --git a/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java index 813fb65641..9bd20e745c 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/persistence/hibernate/FooSortingPersistenceIntegrationTest.java @@ -11,8 +11,6 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Order; import javax.persistence.criteria.Root; -import org.hibernate.Criteria; -import org.hibernate.NullPrecedence; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.junit.After; @@ -151,7 +149,7 @@ public class FooSortingPersistenceIntegrationTest { System.out.println("Id: " + foo.getId() + ", FirstName: " + foo.getName()); } } - + @Test public final void whenCriteriaSortingStringNullsFirstDesc_thenNullsFirst() { final Criteria criteria = session.createCriteria(Foo.class, "FOO"); diff --git a/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java b/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java index b6cde868d3..d3e90a568a 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java @@ -37,14 +37,9 @@ public class SaveMethodsTest { @BeforeClass public static void beforeTests() { - Configuration configuration = new Configuration().addAnnotatedClass(Person.class) - .setProperty("hibernate.dialect", HSQLDialect.class.getName()) - .setProperty("hibernate.connection.driver_class", org.hsqldb.jdbcDriver.class.getName()) - .setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test") - .setProperty("hibernate.connection.username", "sa").setProperty("hibernate.connection.password", "") - .setProperty("hibernate.hbm2ddl.auto", "update"); - ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings( - configuration.getProperties()).build(); + Configuration configuration = new Configuration().addAnnotatedClass(Person.class).setProperty("hibernate.dialect", HSQLDialect.class.getName()).setProperty("hibernate.connection.driver_class", org.hsqldb.jdbcDriver.class.getName()) + .setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test").setProperty("hibernate.connection.username", "sa").setProperty("hibernate.connection.password", "").setProperty("hibernate.hbm2ddl.auto", "update"); + ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } @@ -269,10 +264,10 @@ public class SaveMethodsTest { @After public void tearDown() { - try{ - session.getTransaction().commit(); - session.close(); - }catch(TransactionException ex){ + try { + session.getTransaction().commit(); + session.close(); + } catch (TransactionException ex) { ex.printStackTrace(); } } diff --git a/spring-hibernate5/src/test/java/com/baeldung/persistence/service/FooStoredProceduresIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/persistence/service/FooStoredProceduresIntegrationTest.java index cfd3844079..8ab1b86809 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/persistence/service/FooStoredProceduresIntegrationTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/persistence/service/FooStoredProceduresIntegrationTest.java @@ -96,16 +96,14 @@ public class FooStoredProceduresIntegrationTest { fooService.create(new Foo("NewFooName")); // Stored procedure getFoosByName using createSQLQuery() - List allFoosByName = session.createQuery("CALL GetFoosByName(:fooName)", Foo.class) - .setParameter("fooName", "NewFooName").getResultList(); + List allFoosByName = session.createQuery("CALL GetFoosByName(:fooName)", Foo.class).setParameter("fooName", "NewFooName").getResultList(); for (Foo foo : allFoosByName) { LOGGER.info("getFoosByName() using SQL Query : found => {}", foo.toString()); } // Stored procedure getFoosByName using getNamedQuery() @SuppressWarnings("unchecked") - List allFoosByName2 = session.getNamedQuery("callGetFoosByName").setParameter("fooName", "NewFooName") - .getResultList(); + List allFoosByName2 = session.getNamedQuery("callGetFoosByName").setParameter("fooName", "NewFooName").getResultList(); for (Foo foo : allFoosByName2) { LOGGER.info("getFoosByName() using Native Query : found => {}", foo.toString()); } From 84c71b3dbfd5e25ac7fcf2ddb100decd19e52561 Mon Sep 17 00:00:00 2001 From: Alex Vargas Date: Sat, 11 Mar 2017 13:27:41 -0800 Subject: [PATCH 088/291] Bael 389 - Making Gson field in both classes static (#1366) * Project for " A Guide to the Java API for WebSocket" article * Setting dependencies correctly * Formatting adjustments * Removing tomcat7 maven plugin * Applying formatt - No spaces * BAEL-389 - Building URL dynamically between host and pathname * Setting javax websocket api scope to provided * Make Gson static field --- .../src/main/java/com/baeldung/websocket/MessageDecoder.java | 4 +++- .../src/main/java/com/baeldung/websocket/MessageEncoder.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java index 29ae5b93e6..3bb3c4391d 100644 --- a/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageDecoder.java @@ -8,9 +8,11 @@ import com.baeldung.model.Message; import com.google.gson.Gson; public class MessageDecoder implements Decoder.Text { + + private static Gson gson = new Gson(); + @Override public Message decode(String s) throws DecodeException { - Gson gson = new Gson(); Message message = gson.fromJson(s, Message.class); return message; } diff --git a/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java index bfecc87a96..6e7ba06ff0 100644 --- a/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java +++ b/java-websocket/src/main/java/com/baeldung/websocket/MessageEncoder.java @@ -8,9 +8,11 @@ import com.baeldung.model.Message; import com.google.gson.Gson; public class MessageEncoder implements Encoder.Text { + + private static Gson gson = new Gson(); + @Override public String encode(Message message) throws EncodeException { - Gson gson = new Gson(); String json = gson.toJson(message); return json; } From e8faa73d749804a6a534eb992e3349d8887c6285 Mon Sep 17 00:00:00 2001 From: eugenp Date: Sat, 11 Mar 2017 23:31:41 +0200 Subject: [PATCH 089/291] testing cleanup --- apache-poi/temp.xlsx | Bin 3508 -> 3510 bytes ...disTest.java => JedisIntegrationTest.java} | 4 +- ...RedissonConfigurationIntegrationTest.java} | 2 +- ...Test.java => RedissonIntegrationTest.java} | 2 +- ...a => ResourceEndpointIntegrationTest.java} | 41 ++++-------------- struts2/pom.xml | 4 +- 6 files changed, 16 insertions(+), 37 deletions(-) rename redis/src/test/java/com/baeldung/{JedisTest.java => JedisIntegrationTest.java} (98%) rename redis/src/test/java/com/baeldung/{RedissonConfigurationTest.java => RedissonConfigurationIntegrationTest.java} (97%) rename redis/src/test/java/com/baeldung/{RedissonTest.java => RedissonIntegrationTest.java} (99%) rename spring-security-cache-control/src/test/java/com/baeldung/cachecontrol/{ResourceEndpointTest.java => ResourceEndpointIntegrationTest.java} (50%) diff --git a/apache-poi/temp.xlsx b/apache-poi/temp.xlsx index 5281b2c4de3e395676c86da7df086c5019b7fa52..50307a28c2ae5c64afdcaf6baae59a0648c28c6b 100644 GIT binary patch delta 597 zcmdlYy-k`oz?+#xgn@&DgCS*m_C{V=MrI(rS(mX6%$U56=^RL4ay_$A{i1aX-zuGI zTCgL*^`qXBm%M@X|Ox^^WF=g%~O(CqGm0-p4&P9 zmG7oQC)gKC8%pr1USnIo`toF_D81h1wZ>vGFAgr&xHQi@`jH;XY0i(Em{n_}IAz=O zk7)`fy^Km~tr6Fq&~vGHkwS+Xi=$e7Vv@MBord&IjkoR6X^zUAJPRDy{Uc7D;Fmt2 z`TzYPo5&M$--~C-94|SOt`~RY#Oc3xAJ^1edi}DJv*OoJh3A(VIW8<%@!;Xn_jyH-MPVq1@Fzfjt~Z2Dv!9y56mZ`pw}igOqk7%l*@2oNK{-pP$T%26OS3>~SHRsh}N z%EG|Fi%kWD)@y1dVC0%)7lZcYzAyf!g^|wAM}j t$0G-Jm^`mEC_;K>%58*slNp delta 550 zcmdlcy+xWgz?+#xgn@&DgP|?ZYa_2LBQucRtjkyjW=vkkbPgmixt`gmo;B9#w(AsD z$HIfBy2=$LZzp|r7JB>Z+p@b`o2o30)A@|!cUrz+tZm@mYbu&%d6c7P%PRBS*7>t? zw;j`PNt`0Frjbj!+x+X#NKM)4*AAbHX1Dt$5Fj-3z|z$P;)@@*u-t4EQ}l1~JRJUd zYsbnjx`j^rI>kI3U$R~lXcY>a;8{Oo=g|&-FIDlS)!z^61WY=>Amzi;^0epA2Ejdi z|MkvHZnbHtTX?MS%<-#dmUc^2?%Q8Ir~iDFv8_I%zy16tF;xPBB3@i__OV`1t2f2R z-ZzPk5uXy9w&jFG?u%KQn~c8&O^W~R{&eG}efzu?mNb;{Zx`OVMcCzE%iLY@0p9E! zlCsBoc5*Q?Fzf 4.0.0 com.baeldung - MyStrutsApp + struts 0.0.1-SNAPSHOT pom struts + src/main/java @@ -13,6 +14,7 @@ src/main/resources + maven-compiler-plugin From 494c36939939ef8a937559b4fbc88fdd18114e5b Mon Sep 17 00:00:00 2001 From: eugenp Date: Sat, 11 Mar 2017 23:33:59 +0200 Subject: [PATCH 090/291] ignoring project temporarily --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 193fd8d984..ee7e75d3cf 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ immutables jackson - java-cassandra + javaslang javax-servlets javaxval From 8bb5cfe27596e98411c610cd6c0fa6c51263c42f Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Sat, 11 Mar 2017 19:57:52 -0600 Subject: [PATCH 091/291] BAEL-566: Updated README.md (#1371) * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * BAEL-566: Updated README.md --- algorithms/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/README.md b/algorithms/README.md index 42f696d9be..77ef0209c0 100644 --- a/algorithms/README.md +++ b/algorithms/README.md @@ -2,3 +2,4 @@ - [Dijkstra Algorithm in Java](http://www.baeldung.com/java-dijkstra) - [Introduction to Cobertura](http://www.baeldung.com/cobertura) +- [Ant Colony Optimization](http://www.baeldung.com/java-ant-colony-optimization) From dda35bc510101a78600f141c46a4fbb25aa0bc78 Mon Sep 17 00:00:00 2001 From: lor6 Date: Sun, 12 Mar 2017 09:57:32 +0200 Subject: [PATCH 092/291] update boot versiob (#1365) --- spring-security-mvc-boot/pom.xml | 14 ++++---------- .../src/main/java/org/baeldung/Application.java | 3 +-- .../multiplelogin/MultipleLoginApplication.java | 8 +------- .../CustomUserDetailsServiceIntegrationTest.java | 4 ++-- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/spring-security-mvc-boot/pom.xml b/spring-security-mvc-boot/pom.xml index 16535b09a7..0b113f4cbf 100644 --- a/spring-security-mvc-boot/pom.xml +++ b/spring-security-mvc-boot/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 1.4.4.RELEASE + 1.5.2.RELEASE @@ -27,11 +27,6 @@ org.springframework.boot spring-boot-starter-web - - org.apache.tomcat - tomcat-catalina - ${tomcat.version} - org.springframework.boot spring-boot-starter-tomcat @@ -344,10 +339,9 @@ 1.8 10.13.1.1 1.1.2 - 4.2.0.RELEASE - 4.2.0.RELEASE - 4.2.0.RELEASE - 8.5.11 + 4.2.2.RELEASE + 4.2.2.RELEASE + 4.2.2.RELEASE 1.2 2.4.0 diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java index ae2651c06f..fa10799caa 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java @@ -2,7 +2,6 @@ package org.baeldung; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @@ -11,7 +10,7 @@ import org.springframework.context.annotation.FilterType; @EnableAutoConfiguration @ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.voter.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multiplelogin.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleentrypoints.*") }) -public class Application extends SpringBootServletInitializer { +public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multiplelogin/MultipleLoginApplication.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multiplelogin/MultipleLoginApplication.java index 836336eb71..e9dc541ad3 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/multiplelogin/MultipleLoginApplication.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multiplelogin/MultipleLoginApplication.java @@ -2,7 +2,6 @@ package org.baeldung.multiplelogin; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -10,13 +9,8 @@ import org.springframework.boot.builder.SpringApplicationBuilder; @SpringBootApplication @ComponentScan("org.baeldung.multiplelogin") -public class MultipleLoginApplication extends SpringBootServletInitializer { +public class MultipleLoginApplication { public static void main(String[] args) { SpringApplication.run(MultipleLoginApplication.class, args); } - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(MultipleLoginApplication.class); - } } \ No newline at end of file diff --git a/spring-security-mvc-boot/src/test/java/org/baeldung/web/CustomUserDetailsServiceIntegrationTest.java b/spring-security-mvc-boot/src/test/java/org/baeldung/web/CustomUserDetailsServiceIntegrationTest.java index 616e80e6e9..3dd4b236f9 100644 --- a/spring-security-mvc-boot/src/test/java/org/baeldung/web/CustomUserDetailsServiceIntegrationTest.java +++ b/spring-security-mvc-boot/src/test/java/org/baeldung/web/CustomUserDetailsServiceIntegrationTest.java @@ -11,7 +11,6 @@ import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -19,9 +18,10 @@ import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.context.SpringBootTest; @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = { MvcConfig.class, SecurityConfig.class, PersistenceConfig.class }) +@SpringBootTest(classes = { MvcConfig.class, SecurityConfig.class, PersistenceConfig.class }) @WebAppConfiguration public class CustomUserDetailsServiceIntegrationTest { From 2f3f490453a44adb96ef13ecbb92b90d8cb04af6 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Sun, 12 Mar 2017 15:19:13 +0530 Subject: [PATCH 093/291] Adding ratpack module (#1374) * adding ratpack module * adding pom.xml --- ratpack/build.gradle | 32 +++++++++++++++++ ratpack/pom.xml | 36 +++++++++++++++++++ .../main/java/com/baeldung/Application.java | 22 ++++++++++++ .../java/com/baeldung/ApplicationTest.java | 31 ++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 ratpack/build.gradle create mode 100644 ratpack/pom.xml create mode 100644 ratpack/src/main/java/com/baeldung/Application.java create mode 100644 ratpack/src/test/java/com/baeldung/ApplicationTest.java diff --git a/ratpack/build.gradle b/ratpack/build.gradle new file mode 100644 index 0000000000..29d9633531 --- /dev/null +++ b/ratpack/build.gradle @@ -0,0 +1,32 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "io.ratpack:ratpack-gradle:1.4.5" + } +} + +if (!JavaVersion.current().java8Compatible) { + throw new IllegalStateException("Must be built with Java 8 or higher") +} + +apply plugin: "io.ratpack.ratpack-java" +apply plugin: 'java' + +repositories { + jcenter() +} + +dependencies { + testCompile 'junit:junit:4.11' + runtime "org.slf4j:slf4j-simple:1.7.21" +} + +test { + testLogging { + events 'started', 'passed' + } +} + +mainClassName = "com.baeldung.Application" diff --git a/ratpack/pom.xml b/ratpack/pom.xml new file mode 100644 index 0000000000..0290a25d2b --- /dev/null +++ b/ratpack/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + com.baeldung + ratpack + jar + 1.0-SNAPSHOT + ratpack + http://maven.apache.org + + + UTF-8 + 1.8 + 1.8 + + + + + io.ratpack + ratpack-core + 1.4.5 + + + io.ratpack + ratpack-test + 1.4.5 + + + junit + junit + 4.12 + test + + + + diff --git a/ratpack/src/main/java/com/baeldung/Application.java b/ratpack/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..3a5bf54d00 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/Application.java @@ -0,0 +1,22 @@ +package com.baeldung; + +import ratpack.http.MutableHeaders; +import ratpack.server.RatpackServer; + +public class Application { + + public static void main(String... args) throws Exception { + RatpackServer.start(server -> server.handlers(chain -> chain.all(ctx -> { + MutableHeaders headers = ctx.getResponse().getHeaders(); + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("Accept-Language", "en-us"); + headers.set("Accept-Charset", "UTF-8"); + ctx.next(); + }) + .get(ctx -> ctx.render("Welcome to baeldung ratpack!!!")) + .get(":name", ctx -> ctx.render("Hello " + ctx.getPathTokens().get("name") + "!!!")) + .post(":amount", ctx -> ctx.render(" Amount $" + ctx.getPathTokens().get("amount") + " added successfully !!!")) + )); + } + +} diff --git a/ratpack/src/test/java/com/baeldung/ApplicationTest.java b/ratpack/src/test/java/com/baeldung/ApplicationTest.java new file mode 100644 index 0000000000..f04a51f2bb --- /dev/null +++ b/ratpack/src/test/java/com/baeldung/ApplicationTest.java @@ -0,0 +1,31 @@ +package com.baeldung; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import ratpack.test.MainClassApplicationUnderTest; + +import static org.junit.Assert.assertEquals; + +@RunWith(JUnit4.class) +public class ApplicationTest { + + MainClassApplicationUnderTest appUnderTest = new MainClassApplicationUnderTest(Application.class); + + @Test + public void givenDefaultUrl_getStaticText() { + assertEquals("Welcome to baeldung ratpack!!!", appUnderTest.getHttpClient().getText("/")); + } + + @Test + public void givenDynamicUrl_getDynamicText() { + assertEquals("Hello dummybot!!!", appUnderTest.getHttpClient().getText("/dummybot")); + } + + @After + public void shutdown() { + appUnderTest.close(); + } + +} \ No newline at end of file From dc142e8423638afa7a70e8af8fc09e4246646d35 Mon Sep 17 00:00:00 2001 From: Andrew Evans Date: Sun, 12 Mar 2017 04:24:07 -0600 Subject: [PATCH 094/291] Intro to Spring Groovy Update and Merge (#1369) * javaslang updates * updated repo * clean * clean * clean * clean --- spring-groovy/.gitignore | 7 ++++ spring-groovy/pom.xml | 35 +++++++++++++++++ .../java/com/baeldug/spring_groovy/App.java | 13 +++++++ .../com/baeldug/spring_groovy/TestConfig.java | 8 ++++ .../main/resources/groovyContextConfig.groovy | 5 +++ .../com/baeldug/spring_groovy/AppTest.java | 38 +++++++++++++++++++ 6 files changed, 106 insertions(+) create mode 100644 spring-groovy/.gitignore create mode 100644 spring-groovy/pom.xml create mode 100644 spring-groovy/src/main/java/com/baeldug/spring_groovy/App.java create mode 100644 spring-groovy/src/main/java/com/baeldug/spring_groovy/TestConfig.java create mode 100644 spring-groovy/src/main/resources/groovyContextConfig.groovy create mode 100644 spring-groovy/src/test/java/com/baeldug/spring_groovy/AppTest.java diff --git a/spring-groovy/.gitignore b/spring-groovy/.gitignore new file mode 100644 index 0000000000..c17c227305 --- /dev/null +++ b/spring-groovy/.gitignore @@ -0,0 +1,7 @@ +/target/ +/project/ +.classpath +.settings +.eclipse +.idea +.project diff --git a/spring-groovy/pom.xml b/spring-groovy/pom.xml new file mode 100644 index 0000000000..686633da27 --- /dev/null +++ b/spring-groovy/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + com.baeldug + spring-groovy + 0.0.1-SNAPSHOT + jar + + spring-groovy + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + org.springframework + spring-core + 4.3.6.RELEASE + + + org.springframework.integration + spring-integration-groovy + 4.3.7.RELEASE + + + diff --git a/spring-groovy/src/main/java/com/baeldug/spring_groovy/App.java b/spring-groovy/src/main/java/com/baeldug/spring_groovy/App.java new file mode 100644 index 0000000000..1df6681c42 --- /dev/null +++ b/spring-groovy/src/main/java/com/baeldug/spring_groovy/App.java @@ -0,0 +1,13 @@ +package com.baeldug.spring_groovy; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/spring-groovy/src/main/java/com/baeldug/spring_groovy/TestConfig.java b/spring-groovy/src/main/java/com/baeldug/spring_groovy/TestConfig.java new file mode 100644 index 0000000000..474216de4e --- /dev/null +++ b/spring-groovy/src/main/java/com/baeldug/spring_groovy/TestConfig.java @@ -0,0 +1,8 @@ +package com.baeldug.spring_groovy; + +import org.springframework.stereotype.Component; + +@Component +public class TestConfig { + +} diff --git a/spring-groovy/src/main/resources/groovyContextConfig.groovy b/spring-groovy/src/main/resources/groovyContextConfig.groovy new file mode 100644 index 0000000000..3ac7366876 --- /dev/null +++ b/spring-groovy/src/main/resources/groovyContextConfig.groovy @@ -0,0 +1,5 @@ +beans{ + testString String, 'test' + testNum int, 100 + testObj(i:101,s:'objVal') +} \ No newline at end of file diff --git a/spring-groovy/src/test/java/com/baeldug/spring_groovy/AppTest.java b/spring-groovy/src/test/java/com/baeldug/spring_groovy/AppTest.java new file mode 100644 index 0000000000..19eefb6c0f --- /dev/null +++ b/spring-groovy/src/test/java/com/baeldug/spring_groovy/AppTest.java @@ -0,0 +1,38 @@ +package com.baeldug.spring_groovy; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} From b2b53494388e2674dd104bdddbc8d96783340c2e Mon Sep 17 00:00:00 2001 From: Andrew Evans Date: Sun, 12 Mar 2017 04:24:32 -0600 Subject: [PATCH 095/291] Javaslang Fetched Upstream and Updated (#1368) * javaslang updates * groovy * update and clean from upstream * upate from upstream and clean * update * cleanup * clean --- spring-data-javaslang/.gitignore | 5 + spring-data-javaslang/pom.xml | 133 ++++++++++++++++++ .../com/baeldung/spring_data/model/Book.java | 45 ++++++ .../baeldung/spring_data/model/JavaBook.java | 41 ++++++ .../repository/BookRepository.java | 19 +++ .../repository/JavaBookRepository.java | 17 +++ .../com/baeldung/spring_data_app/MainApp.java | 21 +++ .../spring_data_tests/SpringTests.java | 86 +++++++++++ 8 files changed, 367 insertions(+) create mode 100644 spring-data-javaslang/.gitignore create mode 100644 spring-data-javaslang/pom.xml create mode 100644 spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/Book.java create mode 100644 spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/JavaBook.java create mode 100644 spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/BookRepository.java create mode 100644 spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/JavaBookRepository.java create mode 100644 spring-data-javaslang/src/main/java/com/baeldung/spring_data_app/MainApp.java create mode 100644 spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java diff --git a/spring-data-javaslang/.gitignore b/spring-data-javaslang/.gitignore new file mode 100644 index 0000000000..7ee5423d14 --- /dev/null +++ b/spring-data-javaslang/.gitignore @@ -0,0 +1,5 @@ +/target/ +/project/ +.idea +.classpath +.eclipse diff --git a/spring-data-javaslang/pom.xml b/spring-data-javaslang/pom.xml new file mode 100644 index 0000000000..c265e893cc --- /dev/null +++ b/spring-data-javaslang/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + spring-data-javaslangb + spring-data-javaslangb + 0.0.1-SNAPSHOT + + UTF-8 + 2.19.1 + 3.1 + 2.9.1-01 + 2.3.7-01 + 2.4.8 + 2.0.5 + 4.12 + 1.5.1.RELEASE + 4.3.6.RELEASE + 4.3.6.RELEASE + 4.3.6.RELEASE + ${basedir}/src/test/java + + + org.springframework.boot + spring-boot-starter-parent + 1.5.1.RELEASE + + + + test-app + + verify + + + org.springframework.boot + spring-boot-maven-plugin + + + spring-boot-run + verify + + run + + false + + + + + + + + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + ${project.build.testSourceDirectory} + + + + + + + org.springframework.boot + spring-boot-devtools + true + + + + com.h2database + h2 + 1.4.193 + + + + io.javaslang + javaslang + ${javaslang.version} + + + + org.springframework.data + spring-data-jpa + 1.11.0.RELEASE + + + + org.springframework.boot + spring-boot + ${spring-boot.version} + + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring-boot.version} + + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + + + + org.springframework + spring-context + ${spring-context.version} + + + + org.springframework + spring-core + ${spring-core.version} + + + + junit + junit + ${junit.version} + test + + + \ No newline at end of file diff --git a/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/Book.java b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/Book.java new file mode 100644 index 0000000000..95653abb6c --- /dev/null +++ b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/Book.java @@ -0,0 +1,45 @@ +package com.baeldung.spring_data.model; + +import javaslang.collection.Seq; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; + +@Entity +@Table(name = "book") +public class Book { + + @GeneratedValue + @Id + private Long id; + + private String title; + + private Seq authors; + + + public void setTitle(String title){ + this.title = title; + } + + public String getTitle(){ + return this.title; + } + + public Long getId(){ + return this.id; + } + + public void setAuthors(Seq authors){ + this.authors = authors; + } + + public Seq getAuthors(){ + return this.authors; + } +} diff --git a/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/JavaBook.java b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/JavaBook.java new file mode 100644 index 0000000000..ab99b0d929 --- /dev/null +++ b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/model/JavaBook.java @@ -0,0 +1,41 @@ +package com.baeldung.spring_data.model; + +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +import java.util.List; + +@Entity +@Table(name = "java_book") +public class JavaBook { + + @GeneratedValue + @Id + private Long id; + + private String title; + + @ElementCollection + private List authors; + + + public void setAuthors(List authors){ + this.authors = authors; + } + + public void setTitle(String title){ + this.title = title; + } + + public String getTitle(){ + return this.title; + } + + public Long getId(){ + return this.id; + } +} + diff --git a/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/BookRepository.java b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/BookRepository.java new file mode 100644 index 0000000000..75b6d0b426 --- /dev/null +++ b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/BookRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.spring_data.repository; + +import com.baeldung.spring_data.model.Book; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import javaslang.collection.Seq; +import javaslang.control.Option; + +@Repository +public interface BookRepository extends JpaRepository{ + Book save(Book book); + + Option findById(Long id); + + Option> findByTitleContaining(String title); + +} diff --git a/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/JavaBookRepository.java b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/JavaBookRepository.java new file mode 100644 index 0000000000..a4aeab85ee --- /dev/null +++ b/spring-data-javaslang/src/main/java/com/baeldung/spring_data/repository/JavaBookRepository.java @@ -0,0 +1,17 @@ +package com.baeldung.spring_data.repository; + +import com.baeldung.spring_data.model.JavaBook; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface JavaBookRepository extends JpaRepository{ + JavaBook save(JavaBook book); + + JavaBook findById(Long id); + + List findByTitleContaining(String title); +} \ No newline at end of file diff --git a/spring-data-javaslang/src/main/java/com/baeldung/spring_data_app/MainApp.java b/spring-data-javaslang/src/main/java/com/baeldung/spring_data_app/MainApp.java new file mode 100644 index 0000000000..d8a194e92e --- /dev/null +++ b/spring-data-javaslang/src/main/java/com/baeldung/spring_data_app/MainApp.java @@ -0,0 +1,21 @@ +package com.baeldung.spring_data_app; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableJpaRepositories("com.baeldung.spring_data.repository") +@EnableTransactionManagement +@EntityScan("com.baeldung.spring_data.model") +@SpringBootApplication +public class MainApp { + public static void main(String[] args){ + SpringApplication.run(MainApp.class, args); + } +} diff --git a/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java b/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java new file mode 100644 index 0000000000..59a6c120fa --- /dev/null +++ b/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java @@ -0,0 +1,86 @@ +package com.baeldung.spring_data_tests; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.baeldung.spring_data_app.MainApp; +import com.baeldung.spring_data.model.Book; +import com.baeldung.spring_data.model.JavaBook; +import com.baeldung.spring_data.repository.BookRepository; +import com.baeldung.spring_data.repository.JavaBookRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; + +import javaslang.collection.Seq; +import javaslang.collection.List; +import javaslang.control.Option; + +import java.util.ArrayList; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = MainApp.class,webEnvironment = WebEnvironment.NONE) +public class SpringTests { + + @Autowired + JavaBookRepository javaRepository; + + @Autowired + BookRepository repository; + + @Test + public void should_return_seq(){ + Seq authors = List.of("author1","author2"); + Book testBook = new Book(); + testBook.setTitle("Javaslang in Spring Data Seq Test Return"); + testBook.setAuthors(authors); + Book book = repository.save(testBook); + Option> books = repository.findByTitleContaining("Seq Test"); + assert(!books.isEmpty()); + } + + + @Test + public void should_return_option_with_book(){ + Seq authors = List.of("author1","author2"); + Book testBook = new Book(); + testBook.setTitle("Javaslang in Spring Data"); + testBook.setAuthors(authors); + Book book = repository.save(testBook); + Option retBook = repository.findById(1L); + assert(retBook.isDefined() && !retBook.isEmpty()); + assert(retBook.get() != null); + } + + @Test + public void should_return_list(){ + ArrayList authors = new ArrayList(); + authors.add("author1"); + authors.add("author2"); + JavaBook testBook = new JavaBook(); + testBook.setTitle("Javaslang in Spring Data Seq Return"); + testBook.setAuthors(authors); + JavaBook book = javaRepository.save(testBook); + java.util.List books = javaRepository.findByTitleContaining("Seq"); + assert(!books.isEmpty()); + assert(books.size() == 1); + assert(books.get(0).getTitle().equals("Javaslang in Spring Data Seq Return")); + } + + @Test + public void should_return_book(){ + ArrayList authors = new ArrayList(); + authors.add("author1"); + authors.add("author2"); + JavaBook testBook = new JavaBook(); + testBook.setTitle("Javaslang in Spring Data"); + testBook.setAuthors(authors); + JavaBook book = javaRepository.save(testBook); + JavaBook retBook = javaRepository.findById(1L); + assert(retBook != null); + assert(retBook.getId() == 1L); + assert(retBook.getTitle().contains("Data")); + } +} \ No newline at end of file From 13b8a8f87eef2c7a62bc975fef21ab8619dcebd7 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 12 Mar 2017 13:37:38 +0100 Subject: [PATCH 096/291] Redisson refactor (#1377) --- .../com/baeldung/RedissonIntegrationTest.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java b/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java index 67c0e05a7e..4cacd9dbd0 100644 --- a/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java +++ b/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java @@ -6,7 +6,6 @@ import org.junit.Test; import org.redisson.Redisson; import org.redisson.RedissonMultiLock; import org.redisson.api.*; -import org.redisson.api.listener.MessageListener; import org.redisson.client.RedisClient; import org.redisson.client.RedisConnection; import org.redisson.client.codec.StringCodec; @@ -21,6 +20,7 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class RedissonIntegrationTest { @@ -48,7 +48,7 @@ public class RedissonIntegrationTest { RKeys keys = client.getKeys(); - assert(keys.count() >= 3); + assertTrue(keys.count() >= 3); } @Test @@ -68,7 +68,7 @@ public class RedissonIntegrationTest { keysWithPattern.spliterator(), false).collect(Collectors.toList()); - assert(keyWithPatternList.size() == 3); + assertTrue(keyWithPatternList.size() == 3); } @Test @@ -80,7 +80,7 @@ public class RedissonIntegrationTest { Ledger returnedLedger = bucket.get(); - assert( + assertTrue( returnedLedger != null && returnedLedger.getName().equals("ledger1")); } @@ -94,7 +94,7 @@ public class RedissonIntegrationTest { atomicLong.set(value); Long returnValue = atomicLong.incrementAndGet(); - assert(returnValue == 6L); + assertTrue(returnValue == 6L); } @Test @@ -102,16 +102,11 @@ public class RedissonIntegrationTest { CompletableFuture future = new CompletableFuture<>(); RTopic subscribeTopic = client.getTopic("baeldung"); - subscribeTopic.addListener(new MessageListener() { - @Override - public void onMessage(String channel, CustomMessage customMessage) { - future.complete(customMessage.getMessage()); - } - }); + subscribeTopic.addListener((channel, customMessage) -> future.complete(customMessage.getMessage())); - RTopic recieveTopic = client.getTopic("baeldung"); + RTopic receiveTopic = client.getTopic("baeldung"); long clientsReceivedMessage - = recieveTopic.publish(new CustomMessage("This is a message")); + = receiveTopic.publish(new CustomMessage("This is a message")); assertEquals("This is a message", future.get()); @@ -122,7 +117,7 @@ public class RedissonIntegrationTest { RMap map = client.getMap("ledger"); map.put("123", new Ledger("ledger")); - assert(map.get("123").getName().equals("ledger")); + assertTrue(map.get("123").getName().equals("ledger")); } @Test @@ -130,7 +125,7 @@ public class RedissonIntegrationTest { RSet ledgerSet = client.getSet("ledgerSet"); ledgerSet.add(new Ledger("ledger")); - assert(ledgerSet.contains(new Ledger("ledger"))); + assertTrue(ledgerSet.contains(new Ledger("ledger"))); } @Test @@ -138,17 +133,17 @@ public class RedissonIntegrationTest { RList ledgerList = client.getList("ledgerList"); ledgerList.add(new Ledger("ledger")); - assert(ledgerList.contains(new Ledger("ledger"))); + assertTrue(ledgerList.contains(new Ledger("ledger"))); } @Test public void givenLockSet_thenEnsureCanUnlock(){ RLock lock = client.getLock("lock"); lock.lock(); - assert(lock.isLocked()); + assertTrue(lock.isLocked()); lock.unlock(); - assert(!lock.isLocked()); + assertTrue(!lock.isLocked()); } @Test @@ -163,10 +158,10 @@ public class RedissonIntegrationTest { RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3); lock.lock(); - assert(lock1.isLocked() && lock2.isLocked() && lock3.isLocked()); + assertTrue(lock1.isLocked() && lock2.isLocked() && lock3.isLocked()); lock.unlock(); - assert(!(lock1.isLocked() || lock2.isLocked() || lock3.isLocked())); + assertTrue(!(lock1.isLocked() || lock2.isLocked() || lock3.isLocked())); } @Test @@ -182,7 +177,7 @@ public class RedissonIntegrationTest { List entries = ledgerService.getEntries(10); - assert(entries.size() == 3 && entries.contains("entry1")); + assertTrue(entries.size() == 3 && entries.contains("entry1")); } @Test @@ -197,7 +192,7 @@ public class RedissonIntegrationTest { LedgerLiveObject returnLedger = service.get(LedgerLiveObject.class, "ledger1"); - assert(ledger.getName().equals(returnLedger.getName())); + assertTrue(ledger.getName().equals(returnLedger.getName())); } @Test @@ -209,7 +204,7 @@ public class RedissonIntegrationTest { List result = batch.execute(); RMap map = client.getMap("ledgerMap"); - assert(result.size() > 0 && map.get("1").equals("2")); + assertTrue(result.size() > 0 && map.get("1").equals("2")); } @Test @@ -218,7 +213,7 @@ public class RedissonIntegrationTest { String result = client.getScript().eval(RScript.Mode.READ_ONLY, "return redis.call('get', 'foo')", RScript.ReturnType.VALUE); - assert(result.equals("bar")); + assertTrue(result.equals("bar")); } @Test @@ -232,6 +227,6 @@ public class RedissonIntegrationTest { conn.closeAsync(); client.shutdown(); - assert(testValue.equals("0")); + assertTrue(testValue.equals("0")); } } From 9063961bb43366b98422f56a7de77ab188f7c110 Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Sun, 12 Mar 2017 20:49:43 +0530 Subject: [PATCH 097/291] BAEL-701 updated source after review --- .../test/java/baeldung/com/SimpleTest.java | 28 +++++++++++++++++++ testng/src/test/resources/test_suite.xml | 1 + 2 files changed, 29 insertions(+) create mode 100644 testng/src/test/java/baeldung/com/SimpleTest.java diff --git a/testng/src/test/java/baeldung/com/SimpleTest.java b/testng/src/test/java/baeldung/com/SimpleTest.java new file mode 100644 index 0000000000..24bf3a6f01 --- /dev/null +++ b/testng/src/test/java/baeldung/com/SimpleTest.java @@ -0,0 +1,28 @@ +package baeldung.com; + +import org.testng.Assert; +import org.testng.TestNG; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class SimpleTest extends TestNG { + private int number; + + @BeforeClass + public void setup() { + number = 12; + } + + @AfterClass + public void tearDown() { + number = 0; + } + + @Test + public void givenNumber_whenEven_thenTrue() { + Assert.assertTrue(number % 2 == 0); + } + +} + diff --git a/testng/src/test/resources/test_suite.xml b/testng/src/test/resources/test_suite.xml index 0ccbbd2714..4d0b17cbe8 100644 --- a/testng/src/test/resources/test_suite.xml +++ b/testng/src/test/resources/test_suite.xml @@ -7,6 +7,7 @@ + \ No newline at end of file From 818eeeeb186819570679c0141fe7c84d01fbe7a7 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 12 Mar 2017 17:14:05 +0100 Subject: [PATCH 098/291] Update README.md (#1373) --- spring-security-basic-auth/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-security-basic-auth/README.md b/spring-security-basic-auth/README.md index 54d09dbf32..8aa299f8cc 100644 --- a/spring-security-basic-auth/README.md +++ b/spring-security-basic-auth/README.md @@ -6,7 +6,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Article: -- [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll) - [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) - [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) From 19ff2eb487a5315622595022b7f6e363dba733e9 Mon Sep 17 00:00:00 2001 From: Mihai Emil Andronache Date: Sun, 12 Mar 2017 18:15:29 +0200 Subject: [PATCH 099/291] finite automata example (#1364) --- .../baeldung/automata/FiniteStateMachine.java | 20 +++++ .../automata/RtFiniteStateMachine.java | 30 +++++++ .../java/com/baeldung/automata/RtState.java | 42 ++++++++++ .../com/baeldung/automata/RtTransition.java | 31 +++++++ .../java/com/baeldung/automata/State.java | 29 +++++++ .../com/baeldung/automata/Transition.java | 20 +++++ .../algorithms/RtFiniteStateMachineTest.java | 82 +++++++++++++++++++ 7 files changed, 254 insertions(+) create mode 100644 algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java create mode 100644 algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java create mode 100644 algorithms/src/main/java/com/baeldung/automata/RtState.java create mode 100644 algorithms/src/main/java/com/baeldung/automata/RtTransition.java create mode 100644 algorithms/src/main/java/com/baeldung/automata/State.java create mode 100644 algorithms/src/main/java/com/baeldung/automata/Transition.java create mode 100644 algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java diff --git a/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java b/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java new file mode 100644 index 0000000000..cd287ce3d5 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java @@ -0,0 +1,20 @@ +package com.baeldung.automata; + +/** + * Finite state machine. + */ +public interface FiniteStateMachine { + + /** + * Follow a transition, switch the state of the machine. + * @param c Char. + * @return A new finite state machine with the new state. + */ + FiniteStateMachine switchState(final CharSequence c); + + /** + * Is the current state a final one? + * @return true or false. + */ + boolean canStop(); +} diff --git a/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java b/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java new file mode 100644 index 0000000000..7d2293bb33 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java @@ -0,0 +1,30 @@ +package com.baeldung.automata; + +/** + * Default implementation of a finite state machine. + * This class is immutable and thread-safe. + */ +public final class RtFiniteStateMachine implements FiniteStateMachine { + + /** + * Current state. + */ + private State current; + + /** + * Ctor. + * @param initial Initial state of this machine. + */ + public RtFiniteStateMachine(final State initial) { + this.current = initial; + } + + public FiniteStateMachine switchState(final CharSequence c) { + return new RtFiniteStateMachine(this.current.transit(c)); + } + + public boolean canStop() { + return this.current.isFinal(); + } + +} diff --git a/algorithms/src/main/java/com/baeldung/automata/RtState.java b/algorithms/src/main/java/com/baeldung/automata/RtState.java new file mode 100644 index 0000000000..7057335f80 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/RtState.java @@ -0,0 +1,42 @@ +package com.baeldung.automata; + +import java.util.ArrayList; +import java.util.List; + +/** + * State in a finite state machine. + */ +public final class RtState implements State { + + private List transitions; + private boolean isFinal; + + public RtState() { + this(false); + } + + public RtState(final boolean isFinal) { + this.transitions = new ArrayList<>(); + this.isFinal = isFinal; + } + + public State transit(final CharSequence c) { + for(final Transition t : this.transitions) { + if(t.isPossible(c)) { + return t.state(); + } + } + throw new IllegalArgumentException("Input not accepted: " + c); + } + + public boolean isFinal() { + return this.isFinal; + } + + @Override + public State with(Transition tr) { + this.transitions.add(tr); + return this; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/automata/RtTransition.java b/algorithms/src/main/java/com/baeldung/automata/RtTransition.java new file mode 100644 index 0000000000..f895f02e1a --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/RtTransition.java @@ -0,0 +1,31 @@ +package com.baeldung.automata; + + +/** + * Transition in finite state machine. + */ +public final class RtTransition implements Transition { + + private String rule; + private State next; + + /** + * Ctor. + * @param rule Rule that a character has to meet + * in order to get to the next state. + * @param next Next state. + */ + public RtTransition (String rule, State next) { + this.rule = rule; + this.next = next; + } + + public State state() { + return this.next; + } + + public boolean isPossible(CharSequence c) { + return this.rule.equalsIgnoreCase(String.valueOf(c)); + } + +} diff --git a/algorithms/src/main/java/com/baeldung/automata/State.java b/algorithms/src/main/java/com/baeldung/automata/State.java new file mode 100644 index 0000000000..25dff900d2 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/State.java @@ -0,0 +1,29 @@ +package com.baeldung.automata; + +/** + * State. Part of a finite state machine. + */ +public interface State { + + /** + * Add a Transition to this state. + * @param tr Given transition. + * @return Modified State. + */ + State with(final Transition tr); + + /** + * Follow one of the transitions, to get + * to the next state. + * @param c Character. + * @return State. + * @throws IllegalStateException if the char is not accepted. + */ + State transit(final CharSequence c); + + /** + * Can the automaton stop on this state? + * @return true or false + */ + boolean isFinal(); +} diff --git a/algorithms/src/main/java/com/baeldung/automata/Transition.java b/algorithms/src/main/java/com/baeldung/automata/Transition.java new file mode 100644 index 0000000000..9b34617aa1 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/automata/Transition.java @@ -0,0 +1,20 @@ +package com.baeldung.automata; + +/** + * Transition in a finite State machine. + */ +public interface Transition { + + /** + * Is the transition possible with the given character? + * @param c char. + * @return true or false. + */ + boolean isPossible(final CharSequence c); + + /** + * The state to which this transition leads. + * @return State. + */ + State state(); +} diff --git a/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java b/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java new file mode 100644 index 0000000000..bd867cbef9 --- /dev/null +++ b/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java @@ -0,0 +1,82 @@ +package algorithms; + +import static org.junit.Assert.*; +import org.junit.Test; +import com.baeldung.automata.*; + +/** + * Tests for {@link RtFiniteStateMachine} + */ +public final class RtFiniteStateMachineTest { + + @Test + public void acceptsSimplePair() { + String json = "{\"key\":\"value\"}"; + FiniteStateMachine machine = this.buildJsonStateMachine(); + for (int i=0;i Date: Mon, 13 Mar 2017 08:33:21 +0530 Subject: [PATCH 100/291] Initial commit for Comparator.comparing article. (#1271) * Initial commit for Comparator.comparing article. * Changes in the code as per suggestions in review. --- .../baeldung/java8/comparator/Employee.java | 23 +++ .../java8/comparator/Java8ComparatorTest.java | 192 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 core-java/src/test/java/com/baeldung/java8/comparator/Employee.java create mode 100644 core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java diff --git a/core-java/src/test/java/com/baeldung/java8/comparator/Employee.java b/core-java/src/test/java/com/baeldung/java8/comparator/Employee.java new file mode 100644 index 0000000000..bbc4e3e320 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java8/comparator/Employee.java @@ -0,0 +1,23 @@ +package com.baeldung.java8.comparator; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class Employee implements Comparable{ + String name; + int age; + double salary; + long mobile; + + + @Override + public int compareTo(Employee argEmployee) { + return name.compareTo(argEmployee.getName()); + } +} diff --git a/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java new file mode 100644 index 0000000000..5c338101d8 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java @@ -0,0 +1,192 @@ +package com.baeldung.java8.comparator; + +import java.util.Arrays; +import java.util.Comparator; + +import org.junit.Before; +import org.junit.Test; + +import lombok.Data; +import static org.junit.Assert.assertTrue; + +public class Java8ComparatorTest { + + private Employee[] employees; + private Employee[] employeesArrayWithNulls; + private Employee[] sortedEmployeesByName; + private Employee[] sortedEmployeesByNameDesc; + private Employee[] sortedEmployeesByAge; + private Employee[] sortedEmployeesByMobile; + private Employee[] sortedEmployeesBySalary; + private Employee[] sortedEmployeesArray_WithNullsFirst; + private Employee[] sortedEmployeesArray_WithNullsLast; + private Employee[] sortedEmployeesByNameAge; + private Employee[] someMoreEmployees; + private Employee[] sortedEmployeesByAgeName;; + + @Before + public void initData() { + employees = new Employee[] { new Employee("John", 25, 3000, 9922001), new Employee("Ace", 22, 2000, 5924001), + new Employee("Keith", 35, 4000, 3924401) }; + employeesArrayWithNulls = new Employee[] { new Employee("John", 25, 3000, 9922001), null, new Employee("Ace", 22, 2000, 5924001), + null, new Employee("Keith", 35, 4000, 3924401) }; + + sortedEmployeesByName = new Employee[] { new Employee("Ace", 22, 2000, 5924001), + new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) }; + sortedEmployeesByNameDesc = new Employee[] { new Employee("Keith", 35, 4000, 3924401), new Employee("John", 25, 3000, 9922001), + new Employee("Ace", 22, 2000, 5924001) }; + + sortedEmployeesByAge = new Employee[] { new Employee("Ace", 22, 2000, 5924001), + new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) }; + + sortedEmployeesByMobile = new Employee[] { new Employee("Keith", 35, 4000, 3924401), new Employee("Ace", 22, 2000, 5924001), + new Employee("John", 25, 3000, 9922001), }; + + sortedEmployeesBySalary = new Employee[] { new Employee("Ace", 22, 2000, 5924001), new Employee("John", 25, 3000, 9922001), + new Employee("Keith", 35, 4000, 3924401), }; + + sortedEmployeesArray_WithNullsFirst = new Employee[] { null, null, new Employee("Ace", 22, 2000, 5924001), + new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) }; + sortedEmployeesArray_WithNullsLast = new Employee[] { new Employee("Ace", 22, 2000, 5924001), + new Employee("John", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401), null, null }; + + someMoreEmployees = new Employee[] { new Employee("Jake", 25, 3000, 9922001), new Employee("Jake", 22, 2000, 5924001), + new Employee("Ace", 22, 3000, 6423001), new Employee("Keith", 35, 4000, 3924401) }; + + sortedEmployeesByAgeName = new Employee[] { new Employee("Ace", 22, 3000, 6423001), + new Employee("Jake", 22, 2000, 5924001), new Employee("Jake", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) }; + sortedEmployeesByNameAge = new Employee[] { new Employee("Ace", 22, 3000, 6423001), + new Employee("Jake", 22, 2000, 5924001), new Employee("Jake", 25, 3000, 9922001), new Employee("Keith", 35, 4000, 3924401) }; + } + + @Test + public void givenEmployeeArray_whenUsingComparing_thenCheckingSort() { + Comparator employeeNameComparator = Comparator.comparing(Employee::getName); + Arrays.sort(employees, employeeNameComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByName)); + } + + @Test + public void givenEmployeeArray_whenUsingComparingWithComparator_thenCheckingSort() { + Comparator employeeNameComparator = Comparator.comparing(Employee::getName, (s1, s2) -> { + return s2.compareTo(s1); + }); + Arrays.sort(employees, employeeNameComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); + } + + @Test + public void givenEmployeeArray_whenUsingComparingInt_thenCheckingSort() { + Comparator employeeAgeComparator = Comparator.comparingInt(Employee::getAge); + Arrays.sort(employees, employeeAgeComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByAge)); + } + + @Test + public void givenEmployeeArray_whenUsingComparingLong_thenCheckingSort() { + Comparator employeeMobileComparator = Comparator.comparingLong(Employee::getMobile); + Arrays.sort(employees, employeeMobileComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByMobile)); + } + + @Test + public void givenEmployeeArray_whenUsingComparingDouble_thenCheckingSort() { + Comparator employeeSalaryComparator = Comparator.comparingDouble(Employee::getSalary); + Arrays.sort(employees, employeeSalaryComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesBySalary)); + } + + @Test + public void givenEmployeeArray_whenUsingNaturalOrder_thenCheckingSort() { + Comparator employeeNameComparator = Comparator. naturalOrder(); + Arrays.sort(employees, employeeNameComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByName)); + } + + @Test + public void givenEmployeeArray_whenUsingReverseOrder_thenCheckingSort() { + Comparator employeeNameComparator = Comparator. reverseOrder(); + Arrays.sort(employees, employeeNameComparator); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); + } + + @Test + public void givenEmployeeArray_whenUsingNullFirst_thenCheckingSort() { + Comparator employeeNameComparator = Comparator.comparing(Employee::getName); + Comparator employeeNameComparator_nullFirst = Comparator.nullsFirst(employeeNameComparator); + Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullFirst); +// System.out.println(Arrays.toString(employeesArrayWithNulls)); + assertTrue(Arrays.equals(employeesArrayWithNulls, sortedEmployeesArray_WithNullsFirst)); + } + + @Test + public void givenEmployeeArray_whenUsingNullLast_thenCheckingSort() { + Comparator employeeNameComparator = Comparator.comparing(Employee::getName); + Comparator employeeNameComparator_nullLast = Comparator.nullsLast(employeeNameComparator); + Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullLast); +// System.out.println(Arrays.toString(employeesArrayWithNulls)); + assertTrue(Arrays.equals(employeesArrayWithNulls, sortedEmployeesArray_WithNullsLast)); + } + + @Test + public void givenEmployeeArray_whenUsingThenComparing_thenCheckingSort() { + Comparator employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge).thenComparing(Employee::getName); + + Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator); +// System.out.println(Arrays.toString(someMoreEmployees)); + assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByAgeName)); + } + + @Test + public void givenEmployeeArray_whenUsingThenComparingInt_thenCheckingSort() { + Comparator employee_Name_Age_Comparator = Comparator.comparing(Employee::getName).thenComparingInt(Employee::getAge); + + Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator); +// System.out.println(Arrays.toString(someMoreEmployees)); + assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByNameAge)); + } + + @Before + public void printData() { +// System.out.println("employees"); +// System.out.println(Arrays.toString(employees)); + // +// System.out.println("employeesArrayWithNulls"); +// System.out.println(Arrays.toString(employeesArrayWithNulls)); + // + // System.out.println("sortedEmployeesByName"); + // System.out.println(Arrays.toString(sortedEmployeesByName)); + // + // System.out.println("sortedEmployeesByNameDesc"); + // System.out.println(Arrays.toString(sortedEmployeesByNameDesc)); + // + // System.out.println("sortedEmployeesByAge"); + // System.out.println(Arrays.toString(sortedEmployeesByAge)); + // + // System.out.println("sortedEmployeesByMobile"); + // System.out.println(Arrays.toString(sortedEmployeesByMobile)); + // + // System.out.println("sortedEmployeesBySalary"); + // System.out.println(Arrays.toString(sortedEmployeesBySalary)); + // + // System.out.println("sortedEmployeesArray_WithNullsFirst"); + // System.out.println(Arrays.toString(sortedEmployeesArray_WithNullsFirst)); + // + // System.out.println("sortedEmployeesArray_WithNullsLast"); + // System.out.println(Arrays.toString(sortedEmployeesArray_WithNullsLast)); + // + // System.out.println("sortedEmployeesByNameAge"); + // System.out.println(Arrays.toString(sortedEmployeesByNameAge)); + // +// System.out.println("someMoreEmployees"); +// System.out.println(Arrays.toString(someMoreEmployees)); + // + } +} From d32d3edcc93fbbab1ed368275812d54ab5dc33b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Melo?= Date: Mon, 13 Mar 2017 08:13:45 +0000 Subject: [PATCH 101/291] Java 9 CompletableFuture API Improvements (#1384) --- core-java-9/README.md | 1 + .../future/CompletableFutureTest.java | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 core-java-9/src/test/java/com/baeldung/java9/concurrent/future/CompletableFutureTest.java diff --git a/core-java-9/README.md b/core-java-9/README.md index 53ad79e59c..6e58383a5e 100644 --- a/core-java-9/README.md +++ b/core-java-9/README.md @@ -8,3 +8,4 @@ - [Java 9 Stream API Improvements](http://www.baeldung.com/java-9-stream-api) - [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods) - [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors) +- [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java9-completablefuture-api-improvements/) \ No newline at end of file diff --git a/core-java-9/src/test/java/com/baeldung/java9/concurrent/future/CompletableFutureTest.java b/core-java-9/src/test/java/com/baeldung/java9/concurrent/future/CompletableFutureTest.java new file mode 100644 index 0000000000..b71c211177 --- /dev/null +++ b/core-java-9/src/test/java/com/baeldung/java9/concurrent/future/CompletableFutureTest.java @@ -0,0 +1,74 @@ +package com.baeldung.java9.concurrent.future; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class CompletableFutureTest { + @Test + public void testDelay () throws Exception { + Object input = new Object(); + CompletableFuture future = new CompletableFuture<>(); + future.completeAsync(() -> input, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); + + Thread.sleep(100); + + assertFalse(future.isDone()); + + Thread.sleep(1000); + assertTrue(future.isDone()); + assertSame(input, future.get()); + } + + @Test + public void testTimeoutTriggered () throws Exception { + CompletableFuture future = new CompletableFuture<>(); + future.orTimeout(1, TimeUnit.SECONDS); + + Thread.sleep(1100); + + assertTrue(future.isDone()); + + try { + future.get(); + } catch (ExecutionException e) { + assertTrue(e.getCause() instanceof TimeoutException); + } + } + + @Test + public void testTimeoutNotTriggered () throws Exception { + Object input = new Object(); + CompletableFuture future = new CompletableFuture<>(); + + future.orTimeout(1, TimeUnit.SECONDS); + + Thread.sleep(100); + + future.complete(input); + + Thread.sleep(1000); + + assertTrue(future.isDone()); + assertSame(input, future.get()); + } + + + + @Test + public void completeOnTimeout () throws Exception { + Object input = new Object(); + CompletableFuture future = new CompletableFuture<>(); + future.completeOnTimeout(input, 1, TimeUnit.SECONDS); + + Thread.sleep(1100); + + assertTrue(future.isDone()); + assertSame(input, future.get()); + } +} From 4a773e79cdf94ecc5cf8139e4648b246b3ea40c4 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Mon, 13 Mar 2017 08:27:44 -0500 Subject: [PATCH 102/291] BAEL-393: renamed guice-intro directory to guice (#1385) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml --- .../examples/guice/marker/Communicator.java | 11 -------- {guice-intro => guice}/pom.xml | 4 +-- .../java/com/baeldung/examples/RunGuice.java | 6 +---- .../examples/guice/Communication.java | 25 +++---------------- .../examples/guice/CommunicationMode.java | 0 .../examples/guice/DefaultCommunicator.java | 5 +++- .../guice/EmailCommunicationMode.java | 3 ++- .../examples/guice/IMCommunicationMode.java | 2 +- .../examples/guice/SMSCommunicationMode.java | 3 ++- .../examples/guice/aop/MessageLogger.java | 4 ++- .../guice/aop/MessageSentLoggable.java | 3 ++- .../examples/guice/binding/AOPModule.java | 3 ++- .../examples/guice/binding/BasicModule.java | 3 ++- .../guice/constant/CommunicationModel.java | 3 ++- .../examples/guice/marker/Communicator.java | 14 +++++++++++ .../examples/guice/modules/BasicModule.java | 3 ++- pom.xml | 2 +- 17 files changed, 44 insertions(+), 50 deletions(-) delete mode 100644 guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java rename {guice-intro => guice}/pom.xml (94%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/RunGuice.java (76%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/Communication.java (54%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/CommunicationMode.java (100%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java (93%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java (92%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java (92%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java (92%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java (88%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java (89%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java (92%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java (96%) rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java (86%) create mode 100644 guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java rename {guice-intro => guice}/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java (96%) diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java b/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java deleted file mode 100644 index 239666b6ab..0000000000 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/marker/Communicator.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.baeldung.examples.guice.marker; - -/** - * - * @author Baeldung - */ -public interface Communicator { - - public boolean sendMessage(String message); - -} diff --git a/guice-intro/pom.xml b/guice/pom.xml similarity index 94% rename from guice-intro/pom.xml rename to guice/pom.xml index 1f0d7679b7..df87021794 100644 --- a/guice-intro/pom.xml +++ b/guice/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.baeldung.examples.guice - guice-intro + guice 1.0-SNAPSHOT jar @@ -30,5 +30,5 @@ 1.8 4.1.0 - guice-intro + guice diff --git a/guice-intro/src/main/java/com/baeldung/examples/RunGuice.java b/guice/src/main/java/com/baeldung/examples/RunGuice.java similarity index 76% rename from guice-intro/src/main/java/com/baeldung/examples/RunGuice.java rename to guice/src/main/java/com/baeldung/examples/RunGuice.java index b4b3e8571e..a07447cde8 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/RunGuice.java +++ b/guice/src/main/java/com/baeldung/examples/RunGuice.java @@ -10,7 +10,7 @@ import java.util.Scanner; /** * - * @author Baeldung + * @author baeldung */ public class RunGuice { @@ -18,14 +18,10 @@ public class RunGuice { Injector injector = Guice.createInjector(new BasicModule(), new AOPModule()); Communication comms = injector.getInstance(Communication.class); Scanner scanner = new Scanner(System.in); - System.out.println("Enter your message to be sent; press Q to quit and P to print the message log"); while (true) { String input = scanner.nextLine(); if (input.equalsIgnoreCase("q")) { System.exit(0); - } - if (input.equalsIgnoreCase("p")) { - comms.print(); } else { comms.sendMessage(input); } diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java b/guice/src/main/java/com/baeldung/examples/guice/Communication.java similarity index 54% rename from guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java rename to guice/src/main/java/com/baeldung/examples/guice/Communication.java index c4b17b57d2..7f7cb822d8 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/Communication.java +++ b/guice/src/main/java/com/baeldung/examples/guice/Communication.java @@ -10,7 +10,7 @@ import java.util.logging.Logger; /** * - * @author Baeldung + * @author baeldung */ public class Communication { @@ -19,37 +19,20 @@ public class Communication { @Inject private Logger logger; - private Queue messageLog; - - @Named("CommsUUID") - private String commsID; - @Inject private DefaultCommunicator communicator; public Communication(Boolean keepRecords) { if (keepRecords) { - messageLog = new LinkedList(); + System.out.println("keeping records"); } } public boolean sendMessage(String message) { - if (!message.isEmpty() && messageLog != null) { - messageLog.add(message); - } + return communicator.sendMessage(message); } - - public void print() { - if (messageLog != null) { - for (String message : messageLog) { - logger.info(message); - } - } else { - logger.info("Message logging wasn't enabled"); - } - } - + public DefaultCommunicator getCommunicator() { return this.communicator; } diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java similarity index 100% rename from guice-intro/src/main/java/com/baeldung/examples/guice/CommunicationMode.java rename to guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java b/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java similarity index 93% rename from guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java rename to guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java index 423c24f789..c65644646a 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java +++ b/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java @@ -5,7 +5,10 @@ import com.baeldung.examples.guice.marker.Communicator; import com.google.inject.Inject; import com.google.inject.name.Named; - +/** + * + * @author baeldung + */ public class DefaultCommunicator implements Communicator { private CommunicationMode defaultCommsMode; diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java similarity index 92% rename from guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java rename to guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java index 642ee7ace0..3caca0edcc 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice; import com.baeldung.examples.guice.aop.MessageSentLoggable; @@ -5,7 +6,7 @@ import com.baeldung.examples.guice.constant.CommunicationModel; /** * - * @author Baekdung + * @author baeldung */ public class EmailCommunicationMode implements CommunicationMode { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java similarity index 92% rename from guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java rename to guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java index 9f34e9a241..bc9bd61449 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java @@ -8,7 +8,7 @@ import java.util.logging.Logger; /** * - * @author Baeldung + * @author baeldung */ public class IMCommunicationMode implements CommunicationMode { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java similarity index 92% rename from guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java rename to guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java index 251e249971..28475839dd 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice; import com.baeldung.examples.guice.aop.MessageSentLoggable; @@ -7,7 +8,7 @@ import java.util.logging.Logger; /** * - * @author Baeldung + * @author baeldung */ public class SMSCommunicationMode implements CommunicationMode { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java similarity index 88% rename from guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java rename to guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java index 8926dfa714..2ad5f8b92e 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java +++ b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java @@ -1,12 +1,14 @@ + package com.baeldung.examples.guice.aop; +import com.google.inject.Inject; import java.util.logging.Logger; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * - * @author Baeldung + * @author baeldung */ public class MessageLogger implements MethodInterceptor { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java similarity index 89% rename from guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java rename to guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java index cacf3bde7c..5e5a411d0e 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java +++ b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice.aop; import java.lang.annotation.ElementType; @@ -7,7 +8,7 @@ import java.lang.annotation.Target; /** * - * @author Baeldung + * @author baeldung */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java b/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java similarity index 92% rename from guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java rename to guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java index dc9d258efa..109d9a6389 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice.binding; import com.baeldung.examples.guice.aop.MessageLogger; @@ -7,7 +8,7 @@ import com.google.inject.matcher.Matchers; /** * - * @author Baeldung + * @author baeldung */ public class AOPModule extends AbstractModule { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java b/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java similarity index 96% rename from guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java rename to guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java index 9168195130..93f0fe54ba 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice.binding; import com.baeldung.examples.guice.Communication; @@ -13,7 +14,7 @@ import java.util.logging.Logger; /** * - * @author Baeldung + * @author baeldung */ public class BasicModule extends AbstractModule { diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java b/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java similarity index 86% rename from guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java rename to guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java index b9fa604a32..d12420a0db 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java +++ b/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java @@ -1,8 +1,9 @@ + package com.baeldung.examples.guice.constant; /** * - * @author Baeldung + * @author baeldung */ public enum CommunicationModel { diff --git a/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java b/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java new file mode 100644 index 0000000000..7425f1c283 --- /dev/null +++ b/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.examples.guice.marker; + +/** + * + * @author Tayo + */ +public interface Communicator { + +} diff --git a/guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java b/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java similarity index 96% rename from guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java rename to guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java index 47b3e2e573..ed83cf3649 100644 --- a/guice-intro/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java @@ -1,3 +1,4 @@ + package com.baeldung.examples.guice.modules; import com.baeldung.examples.guice.Communication; @@ -13,7 +14,7 @@ import java.util.logging.Logger; /** * - * @author Baeldung + * @author baeldung */ public class BasicModule extends AbstractModule { diff --git a/pom.xml b/pom.xml index ee7e75d3cf..c12562551f 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ guava guava18 guava19 - guice-intro + guice disruptor handling-spring-static-resources From b6c32dbcd3ac3d70f614beada57fcfb9f5f96562 Mon Sep 17 00:00:00 2001 From: Yasin Date: Mon, 13 Mar 2017 22:42:19 +0530 Subject: [PATCH 103/291] BAEL-718 Quick intro to javatuplesMaster (#1389) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements * BAEL-718 Quick intro to javatuples --- libraries/README.md | 5 + libraries/pom.xml | 119 ++++++++++-------- .../baeldung/javatuples/JavaTuplesTest.java | 118 +++++++++++++++++ 3 files changed, 188 insertions(+), 54 deletions(-) create mode 100644 libraries/README.md create mode 100644 libraries/src/test/java/com/baeldung/javatuples/JavaTuplesTest.java diff --git a/libraries/README.md b/libraries/README.md new file mode 100644 index 0000000000..7b4f7c36ac --- /dev/null +++ b/libraries/README.md @@ -0,0 +1,5 @@ +The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own. + +The code examples related to different libraries should go in a new package. + +Remember, for advanced libraries like JUnit, Jackson, etc. we already have separate modules. Please make sure to have a look at the existing modules in such cases. \ No newline at end of file diff --git a/libraries/pom.xml b/libraries/pom.xml index bfcc9b66d5..c89efa3f66 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -1,60 +1,71 @@ - - - parent-modules - com.baeldung - 1.0.0-SNAPSHOT - - 4.0.0 + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 - libraries - libraries - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - + libraries + libraries + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + - - - - cglib - cglib - ${cglib.version} - - - org.apache.commons - commons-lang3 - ${commons-lang.version} - - - junit - junit - ${junit.version} - test - - - org.jasypt - jasypt - ${jasypt.version} - + + + + cglib + cglib + ${cglib.version} + + + org.apache.commons + commons-lang3 + ${commons-lang.version} + + + junit + junit + ${junit.version} + test + + + org.jasypt + jasypt + ${jasypt.version} + + + org.javatuples + javatuples + ${javatuples.version} + + + + org.assertj + assertj-core + ${assertj.version} + + - - - - 3.2.4 - 3.5 - 4.12 - 1.9.2 - + + 3.2.4 + 3.5 + 4.12 + 1.9.2 + 1.2 + 3.6.2 + diff --git a/libraries/src/test/java/com/baeldung/javatuples/JavaTuplesTest.java b/libraries/src/test/java/com/baeldung/javatuples/JavaTuplesTest.java new file mode 100644 index 0000000000..af4308e188 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/javatuples/JavaTuplesTest.java @@ -0,0 +1,118 @@ +package com.baeldung.javatuples; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; + +import org.javatuples.KeyValue; +import org.javatuples.LabelValue; +import org.javatuples.Pair; +import org.javatuples.Quartet; +import org.javatuples.Triplet; +import org.javatuples.Unit; +import org.junit.Test; + +public class JavaTuplesTest { + + @SuppressWarnings("unused") + @Test + public void whenCreatingTuples_thenCreateTuples() { + Pair pair = new Pair("This is a pair", 55); + Triplet triplet = Triplet.with("hello", 23, 33.2); + + List collectionOfNames = Arrays.asList("john", "doe", "anne", "alex"); + Quartet quartet = Quartet.fromCollection(collectionOfNames); + + Pair pairFromList = Pair.fromIterable(collectionOfNames, 2); + + String[] names = new String[] { "john", "doe", "anne" }; + Triplet triplet2 = Triplet.fromArray(names); + } + + @Test + public void whenGetValuexFromTuples_thenRetriveValueWithType() { + Quartet quartet = Quartet.with("john", 72.5, 32, "1051 SW"); + + String name = quartet.getValue0(); + Integer age = quartet.getValue2(); + assertThat(name).isEqualTo("john"); + assertThat(age).isEqualTo(32); + } + + @Test + public void whenGetKeyValue_thenGetKeyValue() { + KeyValue keyValue = KeyValue.with(5, "F"); + Integer key = keyValue.getKey(); + String value = keyValue.getValue(); + + assertThat(key).isEqualTo(5); + assertThat(value).isEqualTo("F"); + } + + @Test + public void whenGetLabelValue_thenGetLabelValue() { + LabelValue labelValue = LabelValue.with(5, "F"); + Integer key = labelValue.getLabel(); + String value = labelValue.getValue(); + + assertThat(key).isEqualTo(5); + assertThat(value).isEqualTo("F"); + } + + @Test + public void whenGetValueFromTuples_thenRetriveValueWithoutType() { + Quartet quartet = Quartet.with("john", 72.5, 32, "1051 SW"); + + String name = (String) quartet.getValue(0); + Integer age = (Integer) quartet.getValue(2); + assertThat(name).isEqualTo("john"); + assertThat(age).isEqualTo(32); + } + + @Test + public void whenSetValueInTuple_thenGetANewTuple() { + Pair john = Pair.with("john", 32); + Pair alex = john.setAt0("alex"); + assertThat(john.toString()).isNotEqualTo(alex.toString()); + } + + @Test + public void whenAddNewElement_thenCreateNewTuple() { + Pair pair1 = Pair.with("john", 32); + Triplet triplet1 = pair1.add("1051 SW"); + assertThat(triplet1.contains("john")); + assertThat(triplet1.contains(32)); + assertThat(triplet1.contains("1051 SW")); + + Pair pair2 = Pair.with("alex", 45); + Quartet quartet2 = pair1.add(pair2); + assertThat(quartet2.containsAll(pair1)); + assertThat(quartet2.containsAll(pair2)); + + Quartet quartet1 = pair1.add("alex", 45); + assertThat(quartet1.containsAll("alex", "john", 32, 45)); + + Triplet triplet2 = pair1.addAt1("1051 SW"); + assertThat(triplet2.indexOf("john")).isEqualTo(0); + assertThat(triplet2.indexOf("1051 SW")).isEqualTo(1); + assertThat(triplet2.indexOf(32)).isEqualTo(2); + + Unit unit = pair1.removeFrom0(); + assertThat(unit.contains(32)); + } + + @Test + public void whenCallingToList_thenReturnList() { + Quartet quartet = Quartet.with("john", 72.5, 32, "1051 SW"); + List list = quartet.toList(); + assertThat(list.size()).isEqualTo(4); + } + + @Test + public void whenCallingToArray_thenReturnArray() { + Quartet quartet = Quartet.with("john", 72.5, 32, "1051 SW"); + Object[] array = quartet.toArray(); + assertThat(array.length).isEqualTo(4); + } +} From 788e261f928e06f5782b7ffd4aeaf0ac04758fc2 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 13 Mar 2017 20:31:24 +0100 Subject: [PATCH 104/291] Update .travis.yml (#1387) * Update .travis.yml * Update .travis.yml * Update .travis.yml * Update .travis.yml --- .travis.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c2a369a1b3..7da572edf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,11 @@ addons: cache: directories: - .autoconf - - $HOME/.m2 \ No newline at end of file + - $HOME/.m2 + + sudo: required + + env: + global: + JAVA_OPTS="-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" + MAVEN_OPTS="-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" From 15f5037879bb172e9c4a8e03efc6de3f03b2338e Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Mon, 13 Mar 2017 22:26:51 +0100 Subject: [PATCH 105/291] Feature/bael 75 (#1383) * BEAL-75 - Spring Boot Audit Support Source code for http://inprogress.baeldung.com/wp-admin/post.php?post=35337&action=edit * BEAL-75 - Spring Boot Audit Support Update to use SLF4J logger instead of System.out.println * BEAL-75 - Spring Boot Audit Support Give the user the 'ACTUATOR' role so the management endpoints can be viewed when logging on as 'user' * BEAL-75 - Spring Boot Audit Support Update to Spring Boot 1.5.2.RELEASE --- spring-boot-auditing/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-auditing/pom.xml b/spring-boot-auditing/pom.xml index 9307db39ee..0afbe0becc 100644 --- a/spring-boot-auditing/pom.xml +++ b/spring-boot-auditing/pom.xml @@ -12,7 +12,7 @@ org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 1.5.2.RELEASE @@ -187,7 +187,7 @@ UTF-8 1.8 - 4.3.4.RELEASE + 4.3.7.RELEASE 2.2.1 3.1.1 3.3.7-1 From 46b1f93d52103953c9bec989c0cea4feca61e049 Mon Sep 17 00:00:00 2001 From: Johnson Okorie Date: Mon, 13 Mar 2017 23:20:14 +0100 Subject: [PATCH 106/291] BAEL-482 (#1379) * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 * Evaluation artical : Different Types of Bean Injection in Spring * BAEL-482 * BAEL-482 --- redis/src/test/java/com/baeldung/RedissonIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java b/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java index 4cacd9dbd0..766963e5cf 100644 --- a/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java +++ b/redis/src/test/java/com/baeldung/RedissonIntegrationTest.java @@ -104,9 +104,9 @@ public class RedissonIntegrationTest { RTopic subscribeTopic = client.getTopic("baeldung"); subscribeTopic.addListener((channel, customMessage) -> future.complete(customMessage.getMessage())); - RTopic receiveTopic = client.getTopic("baeldung"); + RTopic publishTopic = client.getTopic("baeldung"); long clientsReceivedMessage - = receiveTopic.publish(new CustomMessage("This is a message")); + = publishTopic.publish(new CustomMessage("This is a message")); assertEquals("This is a message", future.get()); From f2f8839708d9637821a86db26d36535514f0988a Mon Sep 17 00:00:00 2001 From: baljeet20 Date: Tue, 14 Mar 2017 15:46:44 +0530 Subject: [PATCH 107/291] BAEL-707 Add the changes as per review comment (#1397) --- xml/src/main/resources/Order.xsd | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xml/src/main/resources/Order.xsd b/xml/src/main/resources/Order.xsd index 16e689a342..81f3e41628 100644 --- a/xml/src/main/resources/Order.xsd +++ b/xml/src/main/resources/Order.xsd @@ -9,11 +9,6 @@ - - - - - From 52ef5b380382566f37977e98c671fe02af5d237d Mon Sep 17 00:00:00 2001 From: lor6 Date: Tue, 14 Mar 2017 15:25:49 +0200 Subject: [PATCH 108/291] remove constructors (#1398) --- .../MultipleEntryPointsSecurityConfig.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java index 9da2ef20e3..eba67706fa 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java @@ -26,10 +26,6 @@ public class MultipleEntryPointsSecurityConfig { @Order(1) public static class App1ConfigurationAdapter extends WebSecurityConfigurerAdapter { - public App1ConfigurationAdapter() { - super(); - } - @Override protected void configure(HttpSecurity http) throws Exception { //@formatter:off @@ -45,10 +41,6 @@ public class MultipleEntryPointsSecurityConfig { @Order(2) public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter { - public App2ConfigurationAdapter() { - super(); - } - protected void configure(HttpSecurity http) throws Exception { //@formatter:off http.antMatcher("/user/**") @@ -67,10 +59,6 @@ public class MultipleEntryPointsSecurityConfig { @Order(3) public static class App3ConfigurationAdapter extends WebSecurityConfigurerAdapter { - public App3ConfigurationAdapter() { - super(); - } - protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/guest/**").authorizeRequests().anyRequest().permitAll(); } From 61660f5d37b045bbfafeef4c037f4fab04f1052e Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Wed, 15 Mar 2017 10:59:55 +0200 Subject: [PATCH 109/291] add update to rest api (#1401) * upgrade to spring boot 1.5.2 * add full update to REST API --- .../svcbook/book/BookController.java | 25 +++++++++--- .../bootstrap/svcbook/book/BookService.java | 39 ++++++++++++------- .../svcrating/rating/RatingController.java | 26 ++++++++++--- .../svcrating/rating/RatingService.java | 28 ++++++++----- 4 files changed, 83 insertions(+), 35 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java index d00f114b8c..192f9c2342 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java @@ -1,11 +1,19 @@ package com.baeldung.spring.cloud.bootstrap.svcbook.book; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - import java.util.List; import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + @RestController @RequestMapping("/books") public class BookController { @@ -13,7 +21,7 @@ public class BookController { @Autowired private BookService bookService; - @GetMapping("") + @GetMapping public List findAllBooks() { return bookService.findAllBooks(); } @@ -23,7 +31,7 @@ public class BookController { return bookService.findBookById(bookId); } - @PostMapping("") + @PostMapping public Book createBook(@RequestBody Book book) { return bookService.createBook(book); } @@ -33,7 +41,12 @@ public class BookController { bookService.deleteBook(bookId); } - @PatchMapping("/{bookId") + @PutMapping("/{bookId}") + public Book updateBook(@RequestBody Book book, @PathVariable Long bookId) { + return bookService.updateBook(book, bookId); + } + + @PatchMapping("/{bookId}") public Book updateBook(@RequestBody Map updates, @PathVariable Long bookId) { return bookService.updateBook(updates, bookId); } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java index cfcbf15757..106fdad5d9 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java @@ -1,13 +1,15 @@ package com.baeldung.spring.cloud.bootstrap.svcbook.book; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import com.google.common.base.Preconditions; @Service @Transactional(readOnly = true) @@ -27,7 +29,7 @@ public class BookService { @Transactional(propagation = Propagation.REQUIRED) public Book createBook(Book book) { - Book newBook = new Book(); + final Book newBook = new Book(); newBook.setTitle(book.getTitle()); newBook.setAuthor(book.getAuthor()); return bookRepository.save(newBook); @@ -40,16 +42,25 @@ public class BookService { @Transactional(propagation = Propagation.REQUIRED) public Book updateBook(Map updates, Long bookId) { - Book book = findBookById(bookId); - updates.keySet().forEach(key -> { - switch (key) { - case "author": - book.setAuthor(updates.get(key)); - break; - case "title": - book.setTitle(updates.get(key)); - } - }); + final Book book = findBookById(bookId); + updates.keySet() + .forEach(key -> { + switch (key) { + case "author": + book.setAuthor(updates.get(key)); + break; + case "title": + book.setTitle(updates.get(key)); + } + }); + return bookRepository.save(book); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Book updateBook(Book book, Long bookId) { + Preconditions.checkNotNull(book); + Preconditions.checkState(book.getId() == bookId); + Preconditions.checkNotNull(bookRepository.findOne(bookId)); return bookRepository.save(book); } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java index 83452ad747..cbfeda49c0 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java @@ -1,11 +1,20 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - import java.util.List; import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + @RestController @RequestMapping("/ratings") public class RatingController { @@ -13,7 +22,7 @@ public class RatingController { @Autowired private RatingService ratingService; - @GetMapping("") + @GetMapping public List findRatingsByBookId(@RequestParam(required = false, defaultValue = "0") Long bookId) { if (bookId.equals(0L)) { return ratingService.findAllRatings(); @@ -21,7 +30,7 @@ public class RatingController { return ratingService.findRatingsByBookId(bookId); } - @PostMapping("") + @PostMapping public Rating createRating(@RequestBody Rating rating) { return ratingService.createRating(rating); } @@ -31,7 +40,12 @@ public class RatingController { ratingService.deleteRating(ratingId); } - @PatchMapping("/{ratingId") + @PutMapping("/{ratingId}") + public Rating updateRating(@RequestBody Rating rating, @PathVariable Long ratingId) { + return ratingService.updateRating(rating, ratingId); + } + + @PatchMapping("/{ratingId}") public Rating updateRating(@RequestBody Map updates, @PathVariable Long ratingId) { return ratingService.updateRating(updates, ratingId); } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java index a2360b7be5..b05d7e2f1f 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java @@ -1,13 +1,15 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import com.google.common.base.Preconditions; @Service @Transactional(readOnly = true) @@ -31,7 +33,7 @@ public class RatingService { @Transactional(propagation = Propagation.REQUIRED) public Rating createRating(Rating rating) { - Rating newRating = new Rating(); + final Rating newRating = new Rating(); newRating.setBookId(rating.getBookId()); newRating.setStars(rating.getStars()); return ratingRepository.save(newRating); @@ -44,14 +46,22 @@ public class RatingService { @Transactional(propagation = Propagation.REQUIRED) public Rating updateRating(Map updates, Long ratingId) { - Rating rating = findRatingById(ratingId); - updates.keySet().forEach(key -> { - switch (key) { + final Rating rating = findRatingById(ratingId); + updates.keySet() + .forEach(key -> { + switch (key) { case "stars": rating.setStars(Integer.parseInt(updates.get(key))); break; - } - }); + } + }); + return ratingRepository.save(rating); + } + + public Rating updateRating(Rating rating, Long ratingId) { + Preconditions.checkNotNull(rating); + Preconditions.checkState(rating.getId() == ratingId); + Preconditions.checkNotNull(ratingRepository.findOne(ratingId)); return ratingRepository.save(rating); } } From 5cd552a16b0631a6f71c3011f5f5b9a50d7355bb Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Wed, 15 Mar 2017 10:51:33 +0100 Subject: [PATCH 110/291] BAEL-634 javassist (#1349) * BEEL-634 javassist dependency * BEEL-634 code for javassist article * BEEL-634 test refinement * BEEL-634 increment lib to newest version * add test that uses reflection to verify * add field * add bytecode to different class --- libraries/pom.xml | 8 +- .../java/com/baeldung/javasisst/Point.java | 17 +++ .../javasisst/ThreeDimensionalPoint.java | 19 +++ .../com/baeldung/javassist/JavasisstTest.java | 119 ++++++++++++++++++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 libraries/src/main/java/com/baeldung/javasisst/Point.java create mode 100644 libraries/src/main/java/com/baeldung/javasisst/ThreeDimensionalPoint.java create mode 100644 libraries/src/test/java/com/baeldung/javassist/JavasisstTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index c89efa3f66..eaae539872 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -23,7 +23,7 @@ - + cglib @@ -51,6 +51,11 @@ javatuples ${javatuples.version} + + org.javassist + javassist + ${javaassist.version} + org.assertj @@ -65,6 +70,7 @@ 4.12 1.9.2 1.2 + 3.21.0-GA 3.6.2 diff --git a/libraries/src/main/java/com/baeldung/javasisst/Point.java b/libraries/src/main/java/com/baeldung/javasisst/Point.java new file mode 100644 index 0000000000..7e5c1cedd5 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/javasisst/Point.java @@ -0,0 +1,17 @@ +package com.baeldung.javasisst; + + +public class Point { + public int x = 0; + public int y = 0; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public void move(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/libraries/src/main/java/com/baeldung/javasisst/ThreeDimensionalPoint.java b/libraries/src/main/java/com/baeldung/javasisst/ThreeDimensionalPoint.java new file mode 100644 index 0000000000..fb24d4b85d --- /dev/null +++ b/libraries/src/main/java/com/baeldung/javasisst/ThreeDimensionalPoint.java @@ -0,0 +1,19 @@ +package com.baeldung.javasisst; + + +public class ThreeDimensionalPoint { + public int x = 0; + public int y = 0; + public int z = 0; + + public ThreeDimensionalPoint(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void move(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/libraries/src/test/java/com/baeldung/javassist/JavasisstTest.java b/libraries/src/test/java/com/baeldung/javassist/JavasisstTest.java new file mode 100644 index 0000000000..da5ae02c56 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/javassist/JavasisstTest.java @@ -0,0 +1,119 @@ +package com.baeldung.javassist; + + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.NotFoundException; +import javassist.bytecode.*; +import org.junit.Test; + +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class JavasisstTest { + @Test + public void givenJavasisstAPI_whenConstructClass_thenGenerateAClassFile() throws CannotCompileException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException { + //given + String classNameWithPackage = "com.baeldung.JavassistGeneratedClass"; + ClassFile cf = new ClassFile(false, classNameWithPackage, null); + cf.setInterfaces(new String[]{"java.lang.Cloneable"}); + + FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I"); + f.setAccessFlags(AccessFlag.PUBLIC); + cf.addField(f); + + //when + String className = "JavassistGeneratedClass.class"; + cf.write(new DataOutputStream(new FileOutputStream(className))); + + //then + ClassPool classPool = ClassPool.getDefault(); + Field[] fields = classPool.makeClass(cf).toClass().getFields(); + assertEquals(fields[0].getName(), "id"); + + String classContent = new String(Files.readAllBytes(Paths.get(className))); + assertTrue(classContent.contains("java/lang/Cloneable")); + } + + @Test + public void givenJavaClass_whenLoadAtByJavassist_thenTraversWholeClass() throws NotFoundException, CannotCompileException, BadBytecode { + //given + ClassPool cp = ClassPool.getDefault(); + ClassFile cf = cp.get("com.baeldung.javasisst.Point").getClassFile(); + MethodInfo minfo = cf.getMethod("move"); + CodeAttribute ca = minfo.getCodeAttribute(); + CodeIterator ci = ca.iterator(); + + //when + List operations = new LinkedList<>(); + while (ci.hasNext()) { + int index = ci.next(); + int op = ci.byteAt(index); + operations.add(Mnemonic.OPCODE[op]); + } + + //then + assertEquals(operations, + Arrays.asList("aload_0", "iload_1", "putfield", "aload_0", "iload_2", "putfield", "return")); + + } + + @Test + public void givenTableOfInstructions_whenAddNewInstruction_thenShouldConstructProperSequence() throws NotFoundException, BadBytecode, CannotCompileException, IllegalAccessException, InstantiationException { + //given + ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.ThreeDimensionalPoint").getClassFile(); + + //when + FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I"); + f.setAccessFlags(AccessFlag.PUBLIC); + cf.addField(f); + + + ClassPool classPool = ClassPool.getDefault(); + Field[] fields = classPool.makeClass(cf).toClass().getFields(); + List fieldsList = Stream.of(fields).map(Field::getName).collect(Collectors.toList()); + assertTrue(fieldsList.contains("id")); + + } + + @Test + public void givenLoadedClass_whenAddConstructorToClass_shouldCreateClassWithConstructor() throws NotFoundException, CannotCompileException, BadBytecode { + //given + ClassFile cf = ClassPool.getDefault().get("com.baeldung.javasisst.Point").getClassFile(); + Bytecode code = new Bytecode(cf.getConstPool()); + code.addAload(0); + code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V"); + code.addReturn(null); + + //when + MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V"); + minfo.setCodeAttribute(code.toCodeAttribute()); + cf.addMethod(minfo); + + //then + CodeIterator ci = code.toCodeAttribute().iterator(); + List operations = new LinkedList<>(); + while (ci.hasNext()) { + int index = ci.next(); + int op = ci.byteAt(index); + operations.add(Mnemonic.OPCODE[op]); + } + + assertEquals(operations, + Arrays.asList("aload_0", "invokespecial", "return")); + + + } +} From f6e570c6cad68b67c31c8995d0af237f5e37f164 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Wed, 15 Mar 2017 15:33:32 +0530 Subject: [PATCH 111/291] adding following modules with updated testcase : DB, Filter, Json (#1410) * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json --- ratpack/build.gradle | 3 ++ ratpack/pom.xml | 51 +++++++++++++------ .../main/java/com/baeldung/Application.java | 50 +++++++++++++----- .../filter/RequestValidatorFilter.java | 16 ++++++ .../java/com/baeldung/model/Employee.java | 44 ++++++++++++++++ ratpack/src/main/resources/DDL.sql | 6 +++ .../java/com/baeldung/ApplicationTest.java | 17 +++++++ 7 files changed, 159 insertions(+), 28 deletions(-) create mode 100644 ratpack/src/main/java/com/baeldung/filter/RequestValidatorFilter.java create mode 100644 ratpack/src/main/java/com/baeldung/model/Employee.java create mode 100644 ratpack/src/main/resources/DDL.sql diff --git a/ratpack/build.gradle b/ratpack/build.gradle index 29d9633531..aeddd5f9f9 100644 --- a/ratpack/build.gradle +++ b/ratpack/build.gradle @@ -4,6 +4,7 @@ buildscript { } dependencies { classpath "io.ratpack:ratpack-gradle:1.4.5" + classpath "com.h2database:h2:1.4.193" } } @@ -19,6 +20,8 @@ repositories { } dependencies { + compile ratpack.dependency('hikari') + compile 'com.h2database:h2:1.4.193' testCompile 'junit:junit:4.11' runtime "org.slf4j:slf4j-simple:1.7.21" } diff --git a/ratpack/pom.xml b/ratpack/pom.xml index 0290a25d2b..bb606b9b11 100644 --- a/ratpack/pom.xml +++ b/ratpack/pom.xml @@ -15,22 +15,41 @@ - - io.ratpack - ratpack-core - 1.4.5 - - - io.ratpack - ratpack-test - 1.4.5 - - - junit - junit - 4.12 - test - + + io.ratpack + ratpack-core + 1.4.5 + + + io.ratpack + ratpack-hikari + 1.4.5 + + + io.ratpack + ratpack-test + 1.4.5 + + + com.h2database + h2 + 1.4.193 + + + junit + junit + 4.12 + test + + + ${project.artifactId} + + + src/main/resources + + + + diff --git a/ratpack/src/main/java/com/baeldung/Application.java b/ratpack/src/main/java/com/baeldung/Application.java index 3a5bf54d00..94709e88e9 100644 --- a/ratpack/src/main/java/com/baeldung/Application.java +++ b/ratpack/src/main/java/com/baeldung/Application.java @@ -1,22 +1,48 @@ package com.baeldung; +import java.util.ArrayList; +import java.util.List; + +import com.baeldung.filter.RequestValidatorFilter; +import com.baeldung.model.Employee; + +import ratpack.guice.Guice; +import ratpack.hikari.HikariModule; +import ratpack.http.MutableHeaders; +import ratpack.jackson.Jackson; import ratpack.http.MutableHeaders; import ratpack.server.RatpackServer; public class Application { - public static void main(String... args) throws Exception { - RatpackServer.start(server -> server.handlers(chain -> chain.all(ctx -> { - MutableHeaders headers = ctx.getResponse().getHeaders(); - headers.set("Access-Control-Allow-Origin", "*"); - headers.set("Accept-Language", "en-us"); - headers.set("Accept-Charset", "UTF-8"); - ctx.next(); - }) - .get(ctx -> ctx.render("Welcome to baeldung ratpack!!!")) - .get(":name", ctx -> ctx.render("Hello " + ctx.getPathTokens().get("name") + "!!!")) - .post(":amount", ctx -> ctx.render(" Amount $" + ctx.getPathTokens().get("amount") + " added successfully !!!")) - )); + public static void main(String[] args) throws Exception { + + List employees = new ArrayList(); + employees.add(new Employee(1L, "Mr", "John Doe")); + employees.add(new Employee(2L, "Mr", "White Snow")); + + + RatpackServer.start( + server -> server.registry(Guice.registry(bindings -> bindings.module(HikariModule.class, config -> { + config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); + config.addDataSourceProperty("URL", + "jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'classpath:/DDL.sql'"); + }))).handlers(chain -> chain + .all( + // ctx -> { + // MutableHeaders headers = + // ctx.getResponse().getHeaders(); + // headers.set("Access-Control-Allow-Origin","*"); + // headers.set("Accept-Language", "en-us"); + // headers.set("Accept-Charset", "UTF-8"); + // ctx.next(); + // } + new RequestValidatorFilter()) + .get(ctx -> ctx.render("Welcome to baeldung ratpack!!!")) + .get("data/employees", ctx -> ctx.render(Jackson.json(employees))) + .get(":name", ctx -> ctx.render("Hello " + ctx.getPathTokens().get("name") + "!!!")) + .post(":amount", ctx -> ctx + .render(" Amount $" + ctx.getPathTokens().get("amount") + " added successfully !!!")))); } } diff --git a/ratpack/src/main/java/com/baeldung/filter/RequestValidatorFilter.java b/ratpack/src/main/java/com/baeldung/filter/RequestValidatorFilter.java new file mode 100644 index 0000000000..0a8b77aa71 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/filter/RequestValidatorFilter.java @@ -0,0 +1,16 @@ +package com.baeldung.filter; + +import ratpack.handling.Context; +import ratpack.handling.Handler; +import ratpack.http.MutableHeaders; + +public class RequestValidatorFilter implements Handler { + + @Override + public void handle(Context ctx) throws Exception { + MutableHeaders headers = ctx.getResponse().getHeaders(); + headers.set("Access-Control-Allow-Origin", "*"); + ctx.next(); + } + +} diff --git a/ratpack/src/main/java/com/baeldung/model/Employee.java b/ratpack/src/main/java/com/baeldung/model/Employee.java new file mode 100644 index 0000000000..c983d8b769 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/model/Employee.java @@ -0,0 +1,44 @@ +package com.baeldung.model; + +import java.io.Serializable; + +public class Employee implements Serializable { + + private static final long serialVersionUID = 3077867088762010705L; + + private Long id; + private String title; + private String name; + + public Employee(Long id, String title, String name) { + super(); + this.id = id; + this.title = title; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/ratpack/src/main/resources/DDL.sql b/ratpack/src/main/resources/DDL.sql new file mode 100644 index 0000000000..af8709ee75 --- /dev/null +++ b/ratpack/src/main/resources/DDL.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS employee; +CREATE TABLE employee ( + id bigint auto_increment primary key, + title varchar(255), + name varchar(255) +) \ No newline at end of file diff --git a/ratpack/src/test/java/com/baeldung/ApplicationTest.java b/ratpack/src/test/java/com/baeldung/ApplicationTest.java index f04a51f2bb..0333441928 100644 --- a/ratpack/src/test/java/com/baeldung/ApplicationTest.java +++ b/ratpack/src/test/java/com/baeldung/ApplicationTest.java @@ -4,10 +4,17 @@ import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import com.baeldung.model.Employee; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import ratpack.test.MainClassApplicationUnderTest; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; +import java.util.List; + @RunWith(JUnit4.class) public class ApplicationTest { @@ -23,6 +30,16 @@ public class ApplicationTest { assertEquals("Hello dummybot!!!", appUnderTest.getHttpClient().getText("/dummybot")); } + @Test + public void givenUrl_getListOfEmployee() throws JsonProcessingException { + List employees = new ArrayList(); + ObjectMapper mapper = new ObjectMapper(); + employees.add(new Employee(1L, "Mr", "John Doe")); + employees.add(new Employee(2L, "Mr", "White Snow")); + + assertEquals(mapper.writeValueAsString(employees), appUnderTest.getHttpClient().getText("/data/employees")); + } + @After public void shutdown() { appUnderTest.close(); From 21aa12753d6fd61061894098bc9e0246a5f94757 Mon Sep 17 00:00:00 2001 From: lor6 Date: Wed, 15 Mar 2017 14:11:37 +0200 Subject: [PATCH 112/291] add entry points (#1413) --- .../MultipleEntryPointsSecurityConfig.java | 31 +++++++++++++-- .../multipleentrypoints/PagesController.java | 12 +++++- .../spring-security-multiple-entry.xml | 38 ++++++++++++++++--- .../multipleHttpElems/loginWithWarning.html | 28 ++++++++++++++ .../multipleHttpElems/multipleHttpLinks.html | 4 +- .../multipleHttpElems/myPrivateUserPage.html | 13 +++++++ .../baeldung/web/MultipleEntryPointsTest.java | 4 +- 7 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/loginWithWarning.html create mode 100644 spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myPrivateUserPage.html diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java index eba67706fa..9f2eba0a2e 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/MultipleEntryPointsSecurityConfig.java @@ -9,6 +9,10 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @EnableWebSecurity @@ -31,10 +35,17 @@ public class MultipleEntryPointsSecurityConfig { //@formatter:off http.antMatcher("/admin/**") .authorizeRequests().anyRequest().hasRole("ADMIN") - .and().httpBasic() + .and().httpBasic().authenticationEntryPoint(authenticationEntryPoint()) .and().exceptionHandling().accessDeniedPage("/403"); //@formatter:on } + + @Bean + public AuthenticationEntryPoint authenticationEntryPoint(){ + BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint(); + entryPoint.setRealmName("admin realm"); + return entryPoint; + } } @Configuration @@ -42,17 +53,31 @@ public class MultipleEntryPointsSecurityConfig { public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { + //@formatter:off http.antMatcher("/user/**") .authorizeRequests().anyRequest().hasRole("USER") - .and().formLogin().loginPage("/userLogin").loginProcessingUrl("/user/login") + .and().formLogin().loginProcessingUrl("/user/login") .failureUrl("/userLogin?error=loginError").defaultSuccessUrl("/user/myUserPage") .and().logout().logoutUrl("/user/logout").logoutSuccessUrl("/multipleHttpLinks") .deleteCookies("JSESSIONID") - .and().exceptionHandling().accessDeniedPage("/403") + .and().exceptionHandling() + .defaultAuthenticationEntryPointFor(loginUrlauthenticationEntryPointWithWarning(), new AntPathRequestMatcher("/user/private/**")) + .defaultAuthenticationEntryPointFor(loginUrlauthenticationEntryPoint(), new AntPathRequestMatcher("/user/general/**")) + .accessDeniedPage("/403") .and().csrf().disable(); //@formatter:on } + + @Bean + public AuthenticationEntryPoint loginUrlauthenticationEntryPoint(){ + return new LoginUrlAuthenticationEntryPoint("/userLogin"); + } + + @Bean + public AuthenticationEntryPoint loginUrlauthenticationEntryPointWithWarning(){ + return new LoginUrlAuthenticationEntryPoint("/userLoginWithWarning"); + } } @Configuration diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java index 3b59678b87..b3462d4061 100644 --- a/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java +++ b/spring-security-mvc-boot/src/main/java/org/baeldung/multipleentrypoints/PagesController.java @@ -16,10 +16,15 @@ public class PagesController { return "multipleHttpElems/myAdminPage"; } - @RequestMapping("/user/myUserPage") + @RequestMapping("/user/general/myUserPage") public String getUserPage() { return "multipleHttpElems/myUserPage"; } + + @RequestMapping("/user/private/myPrivateUserPage") + public String getPrivateUserPage() { + return "multipleHttpElems/myPrivateUserPage"; + } @RequestMapping("/guest/myGuestPage") public String getGuestPage() { @@ -30,6 +35,11 @@ public class PagesController { public String getUserLoginPage() { return "multipleHttpElems/login"; } + + @RequestMapping("/userLoginWithWarning") + public String getUserLoginPageWithWarning() { + return "multipleHttpElems/loginWithWarning"; + } @RequestMapping("/403") public String getAccessDeniedPage() { diff --git a/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml index 1a68bd5c30..c026700810 100644 --- a/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml +++ b/spring-security-mvc-boot/src/main/resources/spring-security-multiple-entry.xml @@ -2,7 +2,7 @@ @@ -14,9 +14,10 @@ - - - + + @@ -24,14 +25,41 @@ + + + + + + + + + + + + + + + + - + + + + + + diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/loginWithWarning.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/loginWithWarning.html new file mode 100644 index 0000000000..a5b2eaf3dc --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/loginWithWarning.html @@ -0,0 +1,28 @@ + + + + +

Login

+

Warning! You are about to access sensible data!

+ +
+ + + + + + + + + + + + + + +
Username:
Password:
+ +
+ + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html index 4a2af1d649..676badb16f 100644 --- a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/multipleHttpLinks.html @@ -8,7 +8,9 @@ Admin page
-User page +User page +
+Private user page
Guest page diff --git a/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myPrivateUserPage.html b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myPrivateUserPage.html new file mode 100644 index 0000000000..52045ec320 --- /dev/null +++ b/spring-security-mvc-boot/src/main/resources/templates/multipleHttpElems/myPrivateUserPage.html @@ -0,0 +1,13 @@ + + + + +Insert title here + + +Welcome user to your private page! Logout + +

+Back to links + + \ No newline at end of file diff --git a/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java index 96d38d4943..050d2363af 100644 --- a/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java +++ b/spring-security-mvc-boot/src/test/java/org/baeldung/web/MultipleEntryPointsTest.java @@ -46,9 +46,9 @@ public class MultipleEntryPointsTest { @Test public void whenTestUserCredentials_thenOk() throws Exception { - mockMvc.perform(get("/user/myUserPage")).andExpect(status().isFound()); + mockMvc.perform(get("/user/general/myUserPage")).andExpect(status().isFound()); - mockMvc.perform(get("/user/myUserPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isOk()); + mockMvc.perform(get("/user/general/myUserPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isOk()); mockMvc.perform(get("/admin/myAdminPage").with(user("user").password("userPass").roles("USER"))).andExpect(status().isForbidden()); } From d1233d04378c7b36a490cc1a7c2f7db52d7e4989 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Wed, 15 Mar 2017 18:11:43 +0530 Subject: [PATCH 113/291] spring boot custom banner (#1412) * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial --- .../src/main/resources/application.properties | 8 ++++++++ spring-boot/src/main/resources/banner.txt | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 spring-boot/src/main/resources/banner.txt diff --git a/spring-boot/src/main/resources/application.properties b/spring-boot/src/main/resources/application.properties index 8c6549f53d..1ffc95849d 100644 --- a/spring-boot/src/main/resources/application.properties +++ b/spring-boot/src/main/resources/application.properties @@ -33,3 +33,11 @@ logging.level.org.springframework=INFO #Servlet Configuration servlet.name=dispatcherExample servlet.mapping=/dispatcherExampleURL + +#banner.charset=UTF-8 +#banner.location=classpath:banner.txt +#banner.image.location=classpath:banner.gif +#banner.image.width= //TODO +#banner.image.height= //TODO +#banner.image.margin= //TODO +#banner.image.invert= //TODO \ No newline at end of file diff --git a/spring-boot/src/main/resources/banner.txt b/spring-boot/src/main/resources/banner.txt new file mode 100644 index 0000000000..c45ff763bf --- /dev/null +++ b/spring-boot/src/main/resources/banner.txt @@ -0,0 +1,19 @@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}:${AnsiColor.WHITE}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}*${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}.${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}:${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}#${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ From de29f6af4b6b8ec756d6d25448dff0eafc311506 Mon Sep 17 00:00:00 2001 From: baljeet20 Date: Thu, 16 Mar 2017 14:32:00 +0530 Subject: [PATCH 114/291] BALE-707 Refactoring changes (#1418) * BAEL-707 Add the changes as per review comment * BAEL-707 Refactored the code as per review comments --- .../java/com/baeldung/xml/jibx/Person.java | 19 ++++----------- .../java/com/baeldung/xml/jibx/Phone.java | 18 --------------- xml/src/main/resources/Order.xsd | 23 ------------------- xml/src/main/resources/customer-binding.xml | 5 +--- .../com/baeldung/xml/jibx/CustomerTest.java | 8 ++----- xml/src/test/resources/Customer1.xml | 7 +----- 6 files changed, 9 insertions(+), 71 deletions(-) diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Person.java b/xml/src/main/java/com/baeldung/xml/jibx/Person.java index 54ce75e257..fbd7cde0a2 100644 --- a/xml/src/main/java/com/baeldung/xml/jibx/Person.java +++ b/xml/src/main/java/com/baeldung/xml/jibx/Person.java @@ -9,23 +9,14 @@ package com.baeldung.xml.jibx; import org.apache.commons.lang.builder.ToStringBuilder; public class Person extends Identity { - private String firstName; - private String lastName; + private String name; - public String getFirstName() { - return firstName; + public String getName() { + return name; } - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; + public void setName(String name) { + this.name = name; } public String toString() { diff --git a/xml/src/main/java/com/baeldung/xml/jibx/Phone.java b/xml/src/main/java/com/baeldung/xml/jibx/Phone.java index b24950289a..783f2ee6fb 100644 --- a/xml/src/main/java/com/baeldung/xml/jibx/Phone.java +++ b/xml/src/main/java/com/baeldung/xml/jibx/Phone.java @@ -2,26 +2,8 @@ package com.baeldung.xml.jibx; public class Phone { - private String countryCode; - private String networkPrefix; private String number; - public String getCountryCode() { - return countryCode; - } - - public void setCountryCode(String countryCode) { - this.countryCode = countryCode; - } - - public String getNetworkPrefix() { - return networkPrefix; - } - - public void setNetworkPrefix(String networkPrefix) { - this.networkPrefix = networkPrefix; - } - public String getNumber() { return number; } diff --git a/xml/src/main/resources/Order.xsd b/xml/src/main/resources/Order.xsd index 81f3e41628..cbb5bc7596 100644 --- a/xml/src/main/resources/Order.xsd +++ b/xml/src/main/resources/Order.xsd @@ -13,29 +13,6 @@ - - - - - - - - - - - - - - - - - - - diff --git a/xml/src/main/resources/customer-binding.xml b/xml/src/main/resources/customer-binding.xml index 54ce4a925f..c1a80366ef 100755 --- a/xml/src/main/resources/customer-binding.xml +++ b/xml/src/main/resources/customer-binding.xml @@ -14,14 +14,11 @@ - - + - - diff --git a/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java b/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java index c678ce8406..8b14277799 100644 --- a/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java +++ b/xml/src/test/java/com/baeldung/xml/jibx/CustomerTest.java @@ -6,7 +6,6 @@ import org.jibx.runtime.IUnmarshallingContext; import org.jibx.runtime.JiBXException; import org.junit.Test; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; @@ -22,8 +21,7 @@ public class CustomerTest { InputStream inputStream = classLoader.getResourceAsStream("Customer1.xml"); Customer customer = (Customer) uctx.unmarshalDocument(inputStream, null); - assertEquals("Stefan", customer.getPerson().getFirstName()); - assertEquals("Jaeger", customer.getPerson().getLastName()); + assertEquals("Stefan Jaegar", customer.getPerson().getName()); assertEquals("Davos Dorf", customer.getCity()); } @@ -47,9 +45,7 @@ public class CustomerTest { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream inputStream = classLoader.getResourceAsStream("Customer1.xml"); Customer customer = (Customer) uctx.unmarshalDocument(inputStream, null); - - assertEquals("1", customer.getHomePhone().getCountryCode()); - assertEquals("234", customer.getHomePhone().getNetworkPrefix()); + assertEquals("234678", customer.getHomePhone().getNumber()); } diff --git a/xml/src/test/resources/Customer1.xml b/xml/src/test/resources/Customer1.xml index 3941563ffe..7f4fbc79af 100644 --- a/xml/src/test/resources/Customer1.xml +++ b/xml/src/test/resources/Customer1.xml @@ -2,18 +2,13 @@ 12345 - Stefan - Jaeger + Stefan Jaeger - 1 - 234 234678 - 1 - 234 234678 Davos Dorf From 26b5ab860a8459bb8f41b05dd3fa2100ce0fa3ea Mon Sep 17 00:00:00 2001 From: ahamedm Date: Thu, 16 Mar 2017 14:49:13 +0400 Subject: [PATCH 115/291] BAEL-696 - Implement OR in the REST API Query Language (#1404) * Dependency Injection Types, XML-Config, Java-Config, Test Classes * Formatting done with Formatter Configuration in Eclipse * REST Query Lang - Adv Search Ops - Improvement - C1 * REST Query Lang - Adv Search Ops - Improvement - C2 * add update to rest api (#1401) * upgrade to spring boot 1.5.2 * add full update to REST API * BAEL-634 javassist (#1349) * BEEL-634 javassist dependency * BEEL-634 code for javassist article * BEEL-634 test refinement * BEEL-634 increment lib to newest version * add test that uses reflection to verify * add field * add bytecode to different class * adding following modules with updated testcase : DB, Filter, Json (#1410) * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * add entry points (#1413) * spring boot custom banner (#1412) * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * BALE-707 Refactoring changes (#1418) * BAEL-707 Add the changes as per review comment * BAEL-707 Refactored the code as per review comments * BAEL-696 Code formatting --- .../beaninjection/AnotherSampleDAOBean.java | 17 ++ .../beaninjection/ExampleDAOBean.java | 39 +++ .../beaninjection/ExampleServiceBean.java | 47 +++ .../beaninjection/IAnotherSampleDAO.java | 5 + .../baeldung/beaninjection/IExampleDAO.java | 12 + .../beaninjection/IExampleService.java | 9 + .../beaninjection/SampleDomainObject.java | 31 ++ ...licationContextTestBeanInjectionTypes.java | 36 +++ .../resources/beaninjectiontypes-context.xml | 22 ++ .../BeanInjectionJavaConfigTest.java | 50 ++++ .../BeanInjectionXMLConfigTest.java | 49 +++ .../persistence/IEnhancedSpecification.java | 10 + .../dao/GenericSpecificationsBuilder.java | 64 ++++ .../persistence/dao/UserSpecification.java | 62 ++-- .../dao/UserSpecificationsBuilder.java | 134 +++++---- .../web/controller/UserController.java | 54 ++-- .../baeldung/web/util/SearchOperation.java | 52 ++-- .../baeldung/web/util/SpecSearchCriteria.java | 105 ++++--- .../JPASpecificationIntegrationTest.java | 279 ++++++++++-------- .../query/JPASpecificationLiveTest.java | 234 ++++++++------- 20 files changed, 898 insertions(+), 413 deletions(-) create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/AnotherSampleDAOBean.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/ExampleDAOBean.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/ExampleServiceBean.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/IAnotherSampleDAO.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/IExampleDAO.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/IExampleService.java create mode 100644 spring-core/src/main/java/com/baeldung/beaninjection/SampleDomainObject.java create mode 100644 spring-core/src/main/java/com/baeldung/configuration/ApplicationContextTestBeanInjectionTypes.java create mode 100644 spring-core/src/main/resources/beaninjectiontypes-context.xml create mode 100644 spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionJavaConfigTest.java create mode 100644 spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionXMLConfigTest.java create mode 100644 spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java create mode 100644 spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/AnotherSampleDAOBean.java b/spring-core/src/main/java/com/baeldung/beaninjection/AnotherSampleDAOBean.java new file mode 100644 index 0000000000..6313ba5a65 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/AnotherSampleDAOBean.java @@ -0,0 +1,17 @@ +package com.baeldung.beaninjection; + +public class AnotherSampleDAOBean implements IAnotherSampleDAO { + + private String propertyY; + + public AnotherSampleDAOBean(String propertyY) { + this.propertyY = propertyY; + } + + // standard setters and getters + + public String getPropertyY() { + return propertyY; + } + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/ExampleDAOBean.java b/spring-core/src/main/java/com/baeldung/beaninjection/ExampleDAOBean.java new file mode 100644 index 0000000000..cbc7b35a7c --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/ExampleDAOBean.java @@ -0,0 +1,39 @@ +package com.baeldung.beaninjection; + +import java.util.List; + +public class ExampleDAOBean implements IExampleDAO { + + private String propertyX; + + public ExampleDAOBean(String propertyX) { + this.propertyX = propertyX; + } + + public String getPropertyX() { + return propertyX; + } + + public void setPropertyX(String propertyX) { + this.propertyX = propertyX; + } + + @Override + public List getDomainList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SampleDomainObject createNewDomain(SampleDomainObject inputDomain) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SampleDomainObject getSomeDomain() { + // TODO Auto-generated method stub + return new SampleDomainObject(); + } + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/ExampleServiceBean.java b/spring-core/src/main/java/com/baeldung/beaninjection/ExampleServiceBean.java new file mode 100644 index 0000000000..e5a5dfff5d --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/ExampleServiceBean.java @@ -0,0 +1,47 @@ +package com.baeldung.beaninjection; + +import java.util.List; + +public class ExampleServiceBean implements IExampleService { + + private IExampleDAO exampleDAO; + private IAnotherSampleDAO anotherSampleDAO; + + public ExampleServiceBean(IExampleDAO exampleDAO) { + this.exampleDAO = exampleDAO; + } + + public void setAnotherSampleDAO(IAnotherSampleDAO anotherSampleDAO) { + this.anotherSampleDAO = anotherSampleDAO; + } + + // standard setters and getters + + public IAnotherSampleDAO getAnotherSampleDAO() { + return anotherSampleDAO; + } + + public void setExampleDAO(ExampleDAOBean exampleDAO) { + this.exampleDAO = exampleDAO; + } + + public IExampleDAO getExampleDAO() { + return exampleDAO; + } + + private String propertyX; + + public String getPropertyX() { + return propertyX; + } + + public void setPropertyX(String propertyX) { + this.propertyX = propertyX; + } + + public List serviceMethodX() { + /*get domain list from DAO .. business logic on domain objects..return*/ + return exampleDAO.getDomainList(); + } + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/IAnotherSampleDAO.java b/spring-core/src/main/java/com/baeldung/beaninjection/IAnotherSampleDAO.java new file mode 100644 index 0000000000..ed4ad42705 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/IAnotherSampleDAO.java @@ -0,0 +1,5 @@ +package com.baeldung.beaninjection; + +public interface IAnotherSampleDAO { + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/IExampleDAO.java b/spring-core/src/main/java/com/baeldung/beaninjection/IExampleDAO.java new file mode 100644 index 0000000000..f7dbd2f9fe --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/IExampleDAO.java @@ -0,0 +1,12 @@ +package com.baeldung.beaninjection; + +import java.util.List; + +public interface IExampleDAO { + + List getDomainList(); + + SampleDomainObject createNewDomain(SampleDomainObject domainObject); + + SampleDomainObject getSomeDomain(); +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/IExampleService.java b/spring-core/src/main/java/com/baeldung/beaninjection/IExampleService.java new file mode 100644 index 0000000000..9ea572d16b --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/IExampleService.java @@ -0,0 +1,9 @@ +package com.baeldung.beaninjection; + +import java.util.List; + +public interface IExampleService { + + List serviceMethodX(); + +} diff --git a/spring-core/src/main/java/com/baeldung/beaninjection/SampleDomainObject.java b/spring-core/src/main/java/com/baeldung/beaninjection/SampleDomainObject.java new file mode 100644 index 0000000000..3a5a913aa6 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/beaninjection/SampleDomainObject.java @@ -0,0 +1,31 @@ +package com.baeldung.beaninjection; + +import java.io.Serializable; + +public class SampleDomainObject implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 449859763481296747L; + + private String domainPropX; + private String domainPropY; + + public String getDomainPropX() { + return domainPropX; + } + + public void setDomainPropX(String domainPropX) { + this.domainPropX = domainPropX; + } + + public String getDomainPropY() { + return domainPropY; + } + + public void setDomainPropY(String domainPropY) { + this.domainPropY = domainPropY; + } + +} diff --git a/spring-core/src/main/java/com/baeldung/configuration/ApplicationContextTestBeanInjectionTypes.java b/spring-core/src/main/java/com/baeldung/configuration/ApplicationContextTestBeanInjectionTypes.java new file mode 100644 index 0000000000..3939abf148 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/configuration/ApplicationContextTestBeanInjectionTypes.java @@ -0,0 +1,36 @@ +package com.baeldung.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.beaninjection.AnotherSampleDAOBean; +import com.baeldung.beaninjection.ExampleDAOBean; +import com.baeldung.beaninjection.ExampleServiceBean; +import com.baeldung.beaninjection.IAnotherSampleDAO; +import com.baeldung.beaninjection.IExampleDAO; +import com.baeldung.beaninjection.IExampleService; + +@Configuration +@ComponentScan(basePackages = { "com.baeldung.beaninjection" }) +public class ApplicationContextTestBeanInjectionTypes { + + @Bean + public IExampleDAO exampleDAO() { + return new ExampleDAOBean("Mandatory DAO Property X"); + } + + @Bean + public IExampleService exampleServiceBean() { + ExampleServiceBean serviceBean = new ExampleServiceBean(exampleDAO()); + serviceBean.setAnotherSampleDAO(anotherSampleDAO()); + serviceBean.setPropertyX("Some Service Property X"); + return serviceBean; + } + + @Bean + public IAnotherSampleDAO anotherSampleDAO() { + return new AnotherSampleDAOBean("Mandatory DAO Property Y"); + } + +} diff --git a/spring-core/src/main/resources/beaninjectiontypes-context.xml b/spring-core/src/main/resources/beaninjectiontypes-context.xml new file mode 100644 index 0000000000..dfdea41cdc --- /dev/null +++ b/spring-core/src/main/resources/beaninjectiontypes-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionJavaConfigTest.java b/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionJavaConfigTest.java new file mode 100644 index 0000000000..4befd884eb --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionJavaConfigTest.java @@ -0,0 +1,50 @@ +package com.baeldung.test.beaninjection; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.beaninjection.AnotherSampleDAOBean; +import com.baeldung.beaninjection.ExampleDAOBean; +import com.baeldung.beaninjection.ExampleServiceBean; +import com.baeldung.configuration.ApplicationContextTestBeanInjectionTypes; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ApplicationContextTestBeanInjectionTypes.class) +public class BeanInjectionJavaConfigTest implements ApplicationContextAware { + + private ApplicationContext beanInjectedContext; + + @Test + public void testDAOInjectionByJava() { + ExampleServiceBean serviceBean = beanInjectedContext.getBean(ExampleServiceBean.class); + assertNotNull("Failed: Constructor Injection,Bean Reference Injection,Java Config, ExampleServiceBean", serviceBean.getExampleDAO()); + assertNotNull("Failed: Constructor Injection,Bean Reference Injection,Java Config, ExampleServiceBean", serviceBean.getAnotherSampleDAO()); + assertTrue("Failed: Constructor Injection,String Property , Java Config", serviceBean.getPropertyX() + .equals("Some Service Property X")); + } + + @Test + public void testPropertyInjectioninDAOByJava() { + ExampleDAOBean daoBean = beanInjectedContext.getBean(ExampleDAOBean.class); + assertTrue("Failed: Constructor Injection,String Property , Java Config", daoBean.getPropertyX() + .equals("Mandatory DAO Property X")); + + AnotherSampleDAOBean anotherDAOBean = beanInjectedContext.getBean(AnotherSampleDAOBean.class); + assertTrue("Failed: Constructor Injection,String Property , XML Config", anotherDAOBean.getPropertyY() + .equals("Mandatory DAO Property Y")); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + // TODO Auto-generated method stub + this.beanInjectedContext = applicationContext; + } +} diff --git a/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionXMLConfigTest.java b/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionXMLConfigTest.java new file mode 100644 index 0000000000..d19a099aad --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/test/beaninjection/BeanInjectionXMLConfigTest.java @@ -0,0 +1,49 @@ +package com.baeldung.test.beaninjection; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.beaninjection.AnotherSampleDAOBean; +import com.baeldung.beaninjection.ExampleDAOBean; +import com.baeldung.beaninjection.ExampleServiceBean; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath:beaninjectiontypes-context.xml") +public class BeanInjectionXMLConfigTest implements ApplicationContextAware { + + private ApplicationContext beanInjectedContext; + + @Test + public void testDAOInjectionByXML() { + ExampleServiceBean serviceBean = beanInjectedContext.getBean(ExampleServiceBean.class); + assertNotNull("Failed: Constructor Injection,Bean Reference Injection,XML Config, ExampleServiceBean", serviceBean.getExampleDAO()); + assertNotNull("Failed: Constructor Injection,Bean Reference Injection,XML Config, ExampleServiceBean", serviceBean.getAnotherSampleDAO()); + assertTrue("Failed: Constructor Injection,String Property , XML Config", serviceBean.getPropertyX() + .equals("Some Service Property X")); + } + + @Test + public void testPropertyInjectioninDAOByXML() { + ExampleDAOBean daoBean = beanInjectedContext.getBean(ExampleDAOBean.class); + assertTrue("Failed: Constructor Injection,String Property , XML Config", daoBean.getPropertyX() + .equals("Mandatory DAO Property X")); + + AnotherSampleDAOBean anotherDAOBean = beanInjectedContext.getBean(AnotherSampleDAOBean.class); + assertTrue("Failed: Constructor Injection,String Property , XML Config", anotherDAOBean.getPropertyY() + .equals("Mandatory DAO Property Y")); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + // TODO Auto-generated method stub + this.beanInjectedContext = applicationContext; + } +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java new file mode 100644 index 0000000000..58d08a161e --- /dev/null +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java @@ -0,0 +1,10 @@ +package org.baeldung.persistence; + +import org.springframework.data.jpa.domain.Specification; + +public interface IEnhancedSpecification extends Specification { + + default boolean isOfLowPrecedence() { + return false; + } +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java new file mode 100644 index 0000000000..4936c2e1c1 --- /dev/null +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java @@ -0,0 +1,64 @@ +package org.baeldung.persistence.dao; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.baeldung.web.util.SearchOperation; +import org.baeldung.web.util.SpecSearchCriteria; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; + +public class GenericSpecificationsBuilder { + + private final List params; + + public GenericSpecificationsBuilder() { + this.params = new ArrayList<>(); + } + + public final GenericSpecificationsBuilder with(final String key, final String operation, final Object value, + final String prefix, final String suffix) { + return with(null, key, operation, value, prefix, suffix); + } + + public final GenericSpecificationsBuilder with(final String precedenceIndicator, final String key, + final String operation, final Object value, final String prefix, final String suffix) { + SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); + if (op != null) { + if (op == SearchOperation.EQUALITY) // the operation may be complex operation + { + final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + + if (startWithAsterisk && endWithAsterisk) { + op = SearchOperation.CONTAINS; + } else if (startWithAsterisk) { + op = SearchOperation.ENDS_WITH; + } else if (endWithAsterisk) { + op = SearchOperation.STARTS_WITH; + } + } + params.add(new SpecSearchCriteria(precedenceIndicator, key, op, value)); + } + return this; + } + + public Specification build(Function> converter) { + + if (params.size() == 0) + return null; + + params.sort((spec0, spec1) -> Boolean.compare(spec0.isLowPrecedence(), spec1.isLowPrecedence())); + + final List> specs = params.stream().map(converter).collect(Collectors.toCollection(ArrayList::new)); + + Specification result = specs.get(0); + + for (int idx = 1; idx < specs.size(); idx++) { + result=params.get(idx).isLowPrecedence()? Specifications.where(result).or(specs.get(idx)): Specifications.where(result).and(specs.get(idx)); + } + return result; + } +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecification.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecification.java index e41c7ca663..2788c46fde 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecification.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecification.java @@ -11,39 +11,39 @@ import org.springframework.data.jpa.domain.Specification; public class UserSpecification implements Specification { - private SpecSearchCriteria criteria; + private SpecSearchCriteria criteria; - public UserSpecification(final SpecSearchCriteria criteria) { - super(); - this.criteria = criteria; - } + public UserSpecification(final SpecSearchCriteria criteria) { + super(); + this.criteria = criteria; + } - public SpecSearchCriteria getCriteria() { - return criteria; - } + public SpecSearchCriteria getCriteria() { + return criteria; + } - @Override - public Predicate toPredicate(final Root root, final CriteriaQuery query, final CriteriaBuilder builder) { - switch (criteria.getOperation()) { - case EQUALITY: - return builder.equal(root.get(criteria.getKey()), criteria.getValue()); - case NEGATION: - return builder.notEqual(root.get(criteria.getKey()), criteria.getValue()); - case GREATER_THAN: - return builder.greaterThan(root. get(criteria.getKey()), criteria.getValue().toString()); - case LESS_THAN: - return builder.lessThan(root. get(criteria.getKey()), criteria.getValue().toString()); - case LIKE: - return builder.like(root. get(criteria.getKey()), criteria.getValue().toString()); - case STARTS_WITH: - return builder.like(root. get(criteria.getKey()), criteria.getValue() + "%"); - case ENDS_WITH: - return builder.like(root. get(criteria.getKey()), "%" + criteria.getValue()); - case CONTAINS: - return builder.like(root. get(criteria.getKey()), "%" + criteria.getValue() + "%"); - default: - return null; - } - } + @Override + public Predicate toPredicate(final Root root, final CriteriaQuery query, final CriteriaBuilder builder) { + switch (criteria.getOperation()) { + case EQUALITY: + return builder.equal(root.get(criteria.getKey()), criteria.getValue()); + case NEGATION: + return builder.notEqual(root.get(criteria.getKey()), criteria.getValue()); + case GREATER_THAN: + return builder.greaterThan(root. get(criteria.getKey()), criteria.getValue().toString()); + case LESS_THAN: + return builder.lessThan(root. get(criteria.getKey()), criteria.getValue().toString()); + case LIKE: + return builder.like(root. get(criteria.getKey()), criteria.getValue().toString()); + case STARTS_WITH: + return builder.like(root. get(criteria.getKey()), criteria.getValue() + "%"); + case ENDS_WITH: + return builder.like(root. get(criteria.getKey()), "%" + criteria.getValue()); + case CONTAINS: + return builder.like(root. get(criteria.getKey()), "%" + criteria.getValue() + "%"); + default: + return null; + } + } } diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java index 3db4267ae0..8a10163f51 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java @@ -1,60 +1,74 @@ -package org.baeldung.persistence.dao; - -import java.util.ArrayList; -import java.util.List; - -import org.baeldung.persistence.model.User; -import org.baeldung.web.util.SearchOperation; -import org.baeldung.web.util.SpecSearchCriteria; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.domain.Specifications; - -public final class UserSpecificationsBuilder { - - private final List params; - - public UserSpecificationsBuilder() { - params = new ArrayList(); - } - - // API - - public final UserSpecificationsBuilder with(final String key, final String operation, final Object value, final String prefix, final String suffix) { - SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); - if (op != null) { - if (op == SearchOperation.EQUALITY) // the operation may be complex operation - { - final boolean startWithAsterisk = prefix.contains("*"); - final boolean endWithAsterisk = suffix.contains("*"); - - if (startWithAsterisk && endWithAsterisk) { - op = SearchOperation.CONTAINS; - } else if (startWithAsterisk) { - op = SearchOperation.ENDS_WITH; - } else if (endWithAsterisk) { - op = SearchOperation.STARTS_WITH; - } - } - params.add(new SpecSearchCriteria(key, op, value)); - } - return this; - } - - public Specification build() { - if (params.size() == 0) { - return null; - } - - final List> specs = new ArrayList>(); - for (final SpecSearchCriteria param : params) { - specs.add(new UserSpecification(param)); - } - - Specification result = specs.get(0); - for (int i = 1; i < specs.size(); i++) { - result = Specifications.where(result).and(specs.get(i)); - } - return result; - } - -} +package org.baeldung.persistence.dao; + +import org.baeldung.persistence.model.User; +import org.baeldung.web.util.SearchOperation; +import org.baeldung.web.util.SpecSearchCriteria; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; + +import java.util.ArrayList; +import java.util.List; + +public final class UserSpecificationsBuilder { + + private final List params; + + public UserSpecificationsBuilder() { + params = new ArrayList(); + } + + // API + + public final UserSpecificationsBuilder with(final String key, final String operation, final Object value, final String prefix, final String suffix) { + return with(null, key, operation, value, prefix, suffix); + } + + public final UserSpecificationsBuilder with(final String precedenceIndicator, final String key, final String operation, final Object value, final String prefix, final String suffix) { + SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); + if (op != null) { + if (op == SearchOperation.EQUALITY) { // the operation may be complex operation + final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + + if (startWithAsterisk && endWithAsterisk) { + op = SearchOperation.CONTAINS; + } else if (startWithAsterisk) { + op = SearchOperation.ENDS_WITH; + } else if (endWithAsterisk) { + op = SearchOperation.STARTS_WITH; + } + } + params.add(new SpecSearchCriteria(precedenceIndicator, key, op, value)); + } + return this; + } + + public Specification build() { + + if (params.size() == 0) + return null; + + params.sort((spec0, spec1) -> { + return Boolean.compare(spec0.isLowPrecedence(), spec1.isLowPrecedence()); + }); + + Specification result = new UserSpecification(params.get(0)); + + for (int i = 1; i < params.size(); i++) { + result = params.get(i).isLowPrecedence() ? Specifications.where(result).or(new UserSpecification(params.get(i))) : Specifications.where(result).and(new UserSpecification(params.get(i))); + + } + + return result; + } + + public final UserSpecificationsBuilder with(UserSpecification spec) { + params.add(spec.getCriteria()); + return this; + } + + public final UserSpecificationsBuilder with(SpecSearchCriteria criteria) { + params.add(criteria); + return this; + } +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java index d20423ddc0..fff089a62b 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java @@ -1,15 +1,12 @@ package org.baeldung.web.controller; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.baeldung.persistence.dao.IUserDAO; -import org.baeldung.persistence.dao.MyUserPredicatesBuilder; -import org.baeldung.persistence.dao.MyUserRepository; -import org.baeldung.persistence.dao.UserRepository; -import org.baeldung.persistence.dao.UserSpecificationsBuilder; +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.querydsl.core.types.Predicate; +import com.querydsl.core.types.dsl.BooleanExpression; +import cz.jirutka.rsql.parser.RSQLParser; +import cz.jirutka.rsql.parser.ast.Node; +import org.baeldung.persistence.dao.*; import org.baeldung.persistence.dao.rsql.CustomRsqlVisitor; import org.baeldung.persistence.model.MyUser; import org.baeldung.persistence.model.User; @@ -20,20 +17,12 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.data.querydsl.binding.QuerydslPredicate; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.*; -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import com.querydsl.core.types.Predicate; -import com.querydsl.core.types.dsl.BooleanExpression; - -import cz.jirutka.rsql.parser.RSQLParser; -import cz.jirutka.rsql.parser.ast.Node; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; //@EnableSpringDataWebSupport @Controller @@ -84,6 +73,25 @@ public class UserController { return dao.findAll(spec); } + @RequestMapping(method = RequestMethod.GET, value = "/users/espec") + @ResponseBody + public List findAllByOptionalSpecification(@RequestParam(value = "search") final String search) { + final Specification spec = resolveSpecification(search); + return dao.findAll(spec); + } + + protected Specification resolveSpecification(String searchParameters) { + + final UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); + final String operationSetExper = Joiner.on("|").join(SearchOperation.SIMPLE_OPERATION_SET); + final Pattern pattern = Pattern.compile("(\\p{Punct}?)(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); + final Matcher matcher = pattern.matcher(searchParameters + ","); + while (matcher.find()) { + builder.with(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(5), matcher.group(4), matcher.group(6)); + } + return builder.build(); + } + @RequestMapping(method = RequestMethod.GET, value = "/myusers") @ResponseBody public Iterable findAllByQuerydsl(@RequestParam(value = "search") final String search) { diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java index 703f9b93f6..41a556c18a 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java @@ -1,24 +1,28 @@ -package org.baeldung.web.util; - -public enum SearchOperation { - EQUALITY, NEGATION, GREATER_THAN, LESS_THAN, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS; - - public static final String[] SIMPLE_OPERATION_SET = { ":", "!", ">", "<", "~" }; - - public static SearchOperation getSimpleOperation(final char input) { - switch (input) { - case ':': - return EQUALITY; - case '!': - return NEGATION; - case '>': - return GREATER_THAN; - case '<': - return LESS_THAN; - case '~': - return LIKE; - default: - return null; - } - } -} +package org.baeldung.web.util; + +public enum SearchOperation { + EQUALITY, NEGATION, GREATER_THAN, LESS_THAN, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS; + + public static final String[] SIMPLE_OPERATION_SET = { ":", "!", ">", "<", "~" }; + + public static final String LOW_PRECEDENCE_INDICATOR="'"; + + public static final String ZERO_OR_MORE_REGEX="*"; + + public static SearchOperation getSimpleOperation(final char input) { + switch (input) { + case ':': + return EQUALITY; + case '!': + return NEGATION; + case '>': + return GREATER_THAN; + case '<': + return LESS_THAN; + case '~': + return LIKE; + default: + return null; + } + } +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java index 4a04d395fa..7dbb66edea 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java @@ -1,44 +1,61 @@ -package org.baeldung.web.util; - -public class SpecSearchCriteria { - - private String key; - private SearchOperation operation; - private Object value; - - public SpecSearchCriteria() { - - } - - public SpecSearchCriteria(final String key, final SearchOperation operation, final Object value) { - super(); - this.key = key; - this.operation = operation; - this.value = value; - } - - public String getKey() { - return key; - } - - public void setKey(final String key) { - this.key = key; - } - - public SearchOperation getOperation() { - return operation; - } - - public void setOperation(final SearchOperation operation) { - this.operation = operation; - } - - public Object getValue() { - return value; - } - - public void setValue(final Object value) { - this.value = value; - } - -} +package org.baeldung.web.util; + +public class SpecSearchCriteria { + + private String key; + private SearchOperation operation; + private Object value; + private boolean lowPrecedence; + + public SpecSearchCriteria() { + + } + + public SpecSearchCriteria(final String key, final SearchOperation operation, final Object value) { + super(); + this.key = key; + this.operation = operation; + this.value = value; + } + + public SpecSearchCriteria(final String lowPrecedenceIndicator, final String key, final SearchOperation operation, final Object value) { + super(); + this.lowPrecedence = lowPrecedenceIndicator != null && lowPrecedenceIndicator.equals(SearchOperation.LOW_PRECEDENCE_INDICATOR); + this.key = key; + this.operation = operation; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(final String key) { + this.key = key; + } + + public SearchOperation getOperation() { + return operation; + } + + public void setOperation(final SearchOperation operation) { + this.operation = operation; + } + + public Object getValue() { + return value; + } + + public void setValue(final Object value) { + this.value = value; + } + + public boolean isLowPrecedence() { + return lowPrecedence; + } + + public void setLowPrecedence(boolean lowPrecedence) { + this.lowPrecedence = lowPrecedence; + } + +} diff --git a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java index 8bd4857e85..e5c408bfdb 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java @@ -1,119 +1,160 @@ -package org.baeldung.persistence.query; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsIn.isIn; -import static org.hamcrest.core.IsNot.not; - -import java.util.List; - -import org.baeldung.persistence.dao.UserRepository; -import org.baeldung.persistence.dao.UserSpecification; -import org.baeldung.persistence.model.User; -import org.baeldung.spring.PersistenceConfig; -import org.baeldung.web.util.SearchOperation; -import org.baeldung.web.util.SpecSearchCriteria; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.jpa.domain.Specifications; -import org.springframework.test.annotation.Rollback; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { PersistenceConfig.class }) -@Transactional -@Rollback -public class JPASpecificationIntegrationTest { - - @Autowired - private UserRepository repository; - - private User userJohn; - - private User userTom; - - @Before - public void init() { - userJohn = new User(); - userJohn.setFirstName("john"); - userJohn.setLastName("doe"); - userJohn.setEmail("john@doe.com"); - userJohn.setAge(22); - repository.save(userJohn); - - userTom = new User(); - userTom.setFirstName("tom"); - userTom.setLastName("doe"); - userTom.setEmail("tom@doe.com"); - userTom.setAge(26); - repository.save(userTom); - } - - @Test - public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.EQUALITY, "john")); - final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe")); - final List results = repository.findAll(Specifications.where(spec).and(spec1)); - - assertThat(userJohn, isIn(results)); - assertThat(userTom, not(isIn(results))); - } - - @Test - public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.NEGATION, "john")); - final List results = repository.findAll(Specifications.where(spec)); - - assertThat(userTom, isIn(results)); - assertThat(userJohn, not(isIn(results))); - } - - @Test - public void givenMinAge_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "25")); - final List results = repository.findAll(Specifications.where(spec)); - - assertThat(userTom, isIn(results)); - assertThat(userJohn, not(isIn(results))); - } - - @Test - public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.STARTS_WITH, "jo")); - final List results = repository.findAll(spec); - - assertThat(userJohn, isIn(results)); - assertThat(userTom, not(isIn(results))); - } - - @Test - public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.ENDS_WITH, "n")); - final List results = repository.findAll(spec); - - assertThat(userJohn, isIn(results)); - assertThat(userTom, not(isIn(results))); - } - - @Test - public void givenFirstNameSubstring_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.CONTAINS, "oh")); - final List results = repository.findAll(spec); - - assertThat(userJohn, isIn(results)); - assertThat(userTom, not(isIn(results))); - } - - @Test - public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { - final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "20")); - final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.LESS_THAN, "25")); - final List results = repository.findAll(Specifications.where(spec).and(spec1)); - - assertThat(userJohn, isIn(results)); - assertThat(userTom, not(isIn(results))); - } -} +package org.baeldung.persistence.query; + +import org.baeldung.persistence.dao.GenericSpecificationsBuilder; +import org.baeldung.persistence.dao.UserRepository; +import org.baeldung.persistence.dao.UserSpecification; +import org.baeldung.persistence.dao.UserSpecificationsBuilder; +import org.baeldung.persistence.model.User; +import org.baeldung.spring.PersistenceConfig; +import org.baeldung.web.util.SearchOperation; +import org.baeldung.web.util.SpecSearchCriteria; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.domain.Specifications; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.function.Function; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.hamcrest.collection.IsIn.isIn; +import static org.hamcrest.core.IsNot.not; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { PersistenceConfig.class }) +@Transactional +@Rollback +public class JPASpecificationIntegrationTest { + + @Autowired + private UserRepository repository; + + private User userJohn; + + private User userTom; + + private User userPercy; + + @Before + public void init() { + userJohn = new User(); + userJohn.setFirstName("john"); + userJohn.setLastName("doe"); + userJohn.setEmail("john@doe.com"); + userJohn.setAge(22); + repository.save(userJohn); + + userTom = new User(); + userTom.setFirstName("tom"); + userTom.setLastName("doe"); + userTom.setEmail("tom@doe.com"); + userTom.setAge(26); + repository.save(userTom); + + userPercy = new User(); + userPercy.setFirstName("percy"); + userPercy.setLastName("blackney"); + userPercy.setEmail("percy@blackney.com"); + userPercy.setAge(30); + repository.save(userPercy); + } + + @Test + public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.EQUALITY, "john")); + final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe")); + final List results = repository.findAll(Specifications.where(spec).and(spec1)); + + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } + + @Test + public void givenFirstOrLastName_whenGettingListOfUsers_thenCorrect() { + UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); + + final SpecSearchCriteria spec = new SpecSearchCriteria("'", "firstName", SearchOperation.EQUALITY, "john"); + final SpecSearchCriteria spec1 = new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe"); + + final List results = repository.findAll(builder.with(spec1).with(spec).build()); + + assertThat(results, hasSize(2)); + assertThat(userJohn, isIn(results)); + assertThat(userTom, isIn(results)); + } + + @Test + public void givenFirstOrLastNameGenericBuilder_whenGettingListOfUsers_thenCorrect() { + GenericSpecificationsBuilder builder = new GenericSpecificationsBuilder(); + Function> converter = UserSpecification::new; + builder.with("'", "firstName", ":", "john", null, null); + builder.with(null, "lastName", ":", "doe", null, null); + + final List results = repository.findAll(builder.build(converter)); + assertThat(results, hasSize(2)); + assertThat(userJohn, isIn(results)); + assertThat(userTom, isIn(results)); + } + + @Test + public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.NEGATION, "john")); + final List results = repository.findAll(Specifications.where(spec)); + + assertThat(userTom, isIn(results)); + assertThat(userJohn, not(isIn(results))); + } + + @Test + public void givenMinAge_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "25")); + final List results = repository.findAll(Specifications.where(spec)); + + assertThat(userTom, isIn(results)); + assertThat(userJohn, not(isIn(results))); + } + + @Test + public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.STARTS_WITH, "jo")); + final List results = repository.findAll(spec); + + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } + + @Test + public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.ENDS_WITH, "n")); + final List results = repository.findAll(spec); + + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } + + @Test + public void givenFirstNameSubstring_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.CONTAINS, "oh")); + final List results = repository.findAll(spec); + + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } + + @Test + public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { + final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "20")); + final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.LESS_THAN, "25")); + final List results = repository.findAll(Specifications.where(spec).and(spec1)); + + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } +} diff --git a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java index 3b85cfb487..55fde80add 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java @@ -1,112 +1,122 @@ -package org.baeldung.persistence.query; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.baeldung.persistence.model.User; -import org.junit.Before; -import org.junit.Test; -import org.springframework.test.context.ActiveProfiles; - -import com.jayway.restassured.RestAssured; -import com.jayway.restassured.response.Response; -import com.jayway.restassured.specification.RequestSpecification; - -//@RunWith(SpringJUnit4ClassRunner.class) -//@ContextConfiguration(classes = { ConfigTest.class, PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class) -@ActiveProfiles("test") -public class JPASpecificationLiveTest { - - // @Autowired - // private UserRepository repository; - - private User userJohn; - - private User userTom; - - private final String URL_PREFIX = "http://localhost:8082/spring-security-rest-full/auth/users/spec?search="; - - @Before - public void init() { - userJohn = new User(); - userJohn.setFirstName("john"); - userJohn.setLastName("doe"); - userJohn.setEmail("john@doe.com"); - userJohn.setAge(22); - // repository.save(userJohn); - - userTom = new User(); - userTom.setFirstName("tom"); - userTom.setLastName("doe"); - userTom.setEmail("tom@doe.com"); - userTom.setAge(26); - // repository.save(userTom); - } - - @Test - public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "firstName:john,lastName:doe"); - final String result = response.body().asString(); - - assertTrue(result.contains(userJohn.getEmail())); - assertFalse(result.contains(userTom.getEmail())); - } - - @Test - public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "firstName!john"); - final String result = response.body().asString(); - - assertTrue(result.contains(userTom.getEmail())); - assertFalse(result.contains(userJohn.getEmail())); - } - - @Test - public void givenMinAge_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "age>25"); - final String result = response.body().asString(); - - assertTrue(result.contains(userTom.getEmail())); - assertFalse(result.contains(userJohn.getEmail())); - } - - @Test - public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "firstName:jo*"); - final String result = response.body().asString(); - - assertTrue(result.contains(userJohn.getEmail())); - assertFalse(result.contains(userTom.getEmail())); - } - - @Test - public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "firstName:*n"); - final String result = response.body().asString(); - - assertTrue(result.contains(userJohn.getEmail())); - assertFalse(result.contains(userTom.getEmail())); - } - - @Test - public void givenFirstNameSubstring_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "firstName:*oh*"); - final String result = response.body().asString(); - - assertTrue(result.contains(userJohn.getEmail())); - assertFalse(result.contains(userTom.getEmail())); - } - - @Test - public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(URL_PREFIX + "age>20,age<25"); - final String result = response.body().asString(); - - assertTrue(result.contains(userJohn.getEmail())); - assertFalse(result.contains(userTom.getEmail())); - } - - private final RequestSpecification givenAuth() { - return RestAssured.given().auth().preemptive().basic("user1", "user1Pass"); - } -} +package org.baeldung.persistence.query; + +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.response.Response; +import com.jayway.restassured.specification.RequestSpecification; +import org.baeldung.persistence.model.User; +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +//@RunWith(SpringJUnit4ClassRunner.class) +//@ContextConfiguration(classes = { ConfigTest.class, +// PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class) +@ActiveProfiles("test") +public class JPASpecificationLiveTest { + + // @Autowired + // private UserRepository repository; + + private User userJohn; + + private User userTom; + + private final String URL_PREFIX = "http://localhost:8082/spring-security-rest-full/auth/users/spec?search="; + + @Before + public void init() { + userJohn = new User(); + userJohn.setFirstName("john"); + userJohn.setLastName("doe"); + userJohn.setEmail("john@doe.com"); + userJohn.setAge(22); + // repository.save(userJohn); + + userTom = new User(); + userTom.setFirstName("tom"); + userTom.setLastName("doe"); + userTom.setEmail("tom@doe.com"); + userTom.setAge(26); + // repository.save(userTom); + } + + private final String EURL_PREFIX = "http://localhost:8082/spring-security-rest-full/auth/users/espec?search="; + + @Test + public void givenFirstOrLastName_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(EURL_PREFIX + "'firstName:john,lastName:doe"); + final String result = response.body().asString(); + assertTrue(result.contains(userJohn.getEmail())); + assertTrue(result.contains(userTom.getEmail())); + } + + @Test + public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "firstName:john,lastName:doe"); + final String result = response.body().asString(); + + assertTrue(result.contains(userJohn.getEmail())); + assertFalse(result.contains(userTom.getEmail())); + } + + @Test + public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "firstName!john"); + final String result = response.body().asString(); + + assertTrue(result.contains(userTom.getEmail())); + assertFalse(result.contains(userJohn.getEmail())); + } + + @Test + public void givenMinAge_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "age>25"); + final String result = response.body().asString(); + + assertTrue(result.contains(userTom.getEmail())); + assertFalse(result.contains(userJohn.getEmail())); + } + + @Test + public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "firstName:jo*"); + final String result = response.body().asString(); + + assertTrue(result.contains(userJohn.getEmail())); + assertFalse(result.contains(userTom.getEmail())); + } + + @Test + public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "firstName:*n"); + final String result = response.body().asString(); + + assertTrue(result.contains(userJohn.getEmail())); + assertFalse(result.contains(userTom.getEmail())); + } + + @Test + public void givenFirstNameSubstring_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "firstName:*oh*"); + final String result = response.body().asString(); + + assertTrue(result.contains(userJohn.getEmail())); + assertFalse(result.contains(userTom.getEmail())); + } + + @Test + public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { + final Response response = givenAuth().get(URL_PREFIX + "age>20,age<25"); + final String result = response.body().asString(); + + assertTrue(result.contains(userJohn.getEmail())); + assertFalse(result.contains(userTom.getEmail())); + } + + private final RequestSpecification givenAuth() { + return RestAssured.given().auth().preemptive().basic("user1", "user1Pass"); + } +} From c2bcb6338481708d3d9502ccbdde11453fbbe991 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Thu, 16 Mar 2017 19:00:27 +0530 Subject: [PATCH 116/291] changing banner format in plain text (#1417) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * changing banner format in plain text * Delete banner.txt~ * Delete b.txt~ --- spring-boot/src/main/resources/banner.txt | 33 ++++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/spring-boot/src/main/resources/banner.txt b/spring-boot/src/main/resources/banner.txt index c45ff763bf..abfa666eb6 100644 --- a/spring-boot/src/main/resources/banner.txt +++ b/spring-boot/src/main/resources/banner.txt @@ -1,19 +1,14 @@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}:${AnsiColor.WHITE}.${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}*${AnsiColor.WHITE}:${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}.${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}:${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}#${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}:${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}o${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.WHITE}*${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BRIGHT_WHITE} ${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BRIGHT_BLACK}o${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.WHITE}o${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.WHITE}*${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_WHITE}.${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}&${AnsiColor.WHITE}:${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}o${AnsiColor.BRIGHT_BLACK}8${AnsiColor.WHITE}*${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}8${AnsiColor.BRIGHT_BLACK}&${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BRIGHT_BLACK}#${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ -${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@${AnsiColor.BLACK}@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@########@@@@@@@@@@@@@@@@@@@@@@@@...@@@@@@@@@:..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@#. @@@@@* *@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@#o @@@@@* @@@@@* @@@:*.*@@@@@@@: *8@@@ @@@@&:.#@. @o**@@@@**:@o*o@@:.:@@@@@:.o#@&*:@@@@ +@@@@@@@@@@@@* @@@@@* 8888 8@ @@@8 #@o 8@# .@ @@* :. @* @@@@ @. : &@ ** .@@@@ +@@@@@@@@@@. @ o@@@@@* *@@@o::& .* 8@@@@. @@ 8@@@@. @* @@@@ @. @@@& * @@@@# .@@@@ +@@@@@@@@@& @ @@@@@@* @@@@@@ 8 @@@@ .. o&&&&&&& @@ #@@@@. @* @@@@ @. @@@# * @@@@@ .@@@@ +@@@@@@@@@ @@o @@@@@@@* oooo* 8 @@@& @* @@@ # 88. 88. *& o#: @. @@@# *@ &#& .@@@@ +@@@@@@@@# @@@8 @@@@@@@* .*@@@#. *@@ @@@& :#@@@o .@@: *&@8 @o o@@: @. @@@# *@@#. :8# .@@@@ +@@@@@@@@@ @@@@ &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# o@@@@ @@@@@ +@@@@@& &@@@@ 8@@@@@@@@@8&8@@@@@#8#@@@o8@#&@@o&@@@&@@8@@&@@@@88@@8#@8&@@##@@@@@@#8@@#8@@88@@@@@ *@@@@@@@ +@@@# #@@@@#. @@@@@@@@@@@@@8@@8#o@&#@@@@o.@o*@@*.@@@.@&:8o8*@@@8&@@#@@@8@@@@8@#@@@8&@@@@@@#@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \ No newline at end of file From 6aefd62288e64513319d467af0deded953ba972f Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Thu, 16 Mar 2017 19:29:32 +0100 Subject: [PATCH 117/291] Update .travis.yml (#1419) --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7da572edf9..6063fbf3e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ install: travis_wait 40 mvn -q clean install -Dgib.enabled=true jdk: - oraclejdk8 -sudo: false addons: apt: packages: From dbc2c49fe2af9ac0bfb7def7fa3730e8f4e6727f Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Fri, 17 Mar 2017 00:04:53 +0530 Subject: [PATCH 118/291] BAEL-578: Add spring-kafka module (#1407) --- spring-kafka/README.md | 9 +++ spring-kafka/pom.xml | 46 ++++++++++++ .../spring/kafka/KafkaApplication.java | 72 +++++++++++++++++++ .../spring/kafka/KafkaConsumerConfig.java | 45 ++++++++++++ .../spring/kafka/KafkaProducerConfig.java | 36 ++++++++++ .../src/main/resources/application.properties | 2 + 6 files changed, 210 insertions(+) create mode 100644 spring-kafka/README.md create mode 100644 spring-kafka/pom.xml create mode 100644 spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java create mode 100644 spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java create mode 100644 spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java create mode 100644 spring-kafka/src/main/resources/application.properties diff --git a/spring-kafka/README.md b/spring-kafka/README.md new file mode 100644 index 0000000000..2731eca042 --- /dev/null +++ b/spring-kafka/README.md @@ -0,0 +1,9 @@ +# Spring Kakfa + +This is a simple Spring Boot app to demonstrate sending and receiving of messages in Kafka using spring-kafka. + +As Kafka topics are not created automatically by default, this application requires that a topic named 'baeldung' is created manually. + +`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic baeldung` + +Two listeners with group Ids **foo** and **bar** are configured. When run successfully, the *Hello World!* message will be received by both the listeners and logged on console. diff --git a/spring-kafka/pom.xml b/spring-kafka/pom.xml new file mode 100644 index 0000000000..73eaf3acff --- /dev/null +++ b/spring-kafka/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + com.baeldung + spring-kafka + 0.0.1-SNAPSHOT + + spring-kafka + Intro to Kafka with Spring + + + 1.8 + 1.1.3.RELEASE + + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.kafka + spring-kafka + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java new file mode 100644 index 0000000000..252054a9f1 --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java @@ -0,0 +1,72 @@ +package com.baeldung.spring.kafka; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.core.KafkaTemplate; + +@SpringBootApplication +public class KafkaApplication { + + public static void main(String[] args) throws Exception { + ConfigurableApplicationContext context = SpringApplication.run(KafkaApplication.class, args); + MessageProducer producer = context.getBean(MessageProducer.class); + producer.sendMessage("Hello, World!"); + + MessageListener listener = context.getBean(MessageListener.class); + listener.latch.await(20, TimeUnit.SECONDS); + Thread.sleep(60000); + context.close(); + + } + + @Bean + public MessageProducer messageProducer() { + return new MessageProducer(); + } + + @Bean + public MessageListener messageListener() { + return new MessageListener(); + } + + public static class MessageProducer { + + @Autowired + private KafkaTemplate kafkaTemplate; + + @Value(value = "${message.topic.name}") + private String topicName; + + public void sendMessage(String message) { + kafkaTemplate.send(topicName, message); + } + + } + + public static class MessageListener { + + private CountDownLatch latch = new CountDownLatch(2); + + @KafkaListener(topics = "${message.topic.name}", group = "foo", containerFactory = "fooKafkaListenerContainerFactory") + public void listenGroupFoo(String message) { + System.out.println("Received Messasge in group 'foo': " + message); + latch.countDown(); + } + + @KafkaListener(topics = "${message.topic.name}", group = "bar", containerFactory = "barKafkaListenerContainerFactory") + public void listenGroupBar(String message) { + System.out.println("Received Messasge in group 'bar': " + message); + latch.countDown(); + } + + } + +} diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java new file mode 100644 index 0000000000..f9edda2435 --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java @@ -0,0 +1,45 @@ +package com.baeldung.spring.kafka; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; + +@EnableKafka +@Configuration +public class KafkaConsumerConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + public ConsumerFactory consumerFactory(String groupId) { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + return new DefaultKafkaConsumerFactory<>(props); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory fooKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory("foo")); + return factory; + } + + @Bean + public ConcurrentKafkaListenerContainerFactory barKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory("bar")); + return factory; + } +} diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java new file mode 100644 index 0000000000..4f9f9719ee --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.kafka; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; + +@Configuration +public class KafkaProducerConfig { + + @Value(value = "${kafka.bootstrapAddress}") + private String bootstrapAddress; + + @Bean + public ProducerFactory producerFactory() { + Map configProps = new HashMap(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + return new DefaultKafkaProducerFactory(configProps); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + KafkaTemplate template = + new KafkaTemplate(producerFactory()); + return template; + } +} diff --git a/spring-kafka/src/main/resources/application.properties b/spring-kafka/src/main/resources/application.properties new file mode 100644 index 0000000000..a1d73b204c --- /dev/null +++ b/spring-kafka/src/main/resources/application.properties @@ -0,0 +1,2 @@ +kafka.bootstrapAddress=localhost:9092 +message.topic.name=baeldung From a794db3183eee1b46f773f7290ca111868184fd8 Mon Sep 17 00:00:00 2001 From: lor6 Date: Fri, 17 Mar 2017 04:30:52 +0200 Subject: [PATCH 119/291] internationalization app (#1394) --- spring-boot/pom.xml | 2 +- .../InternationalizationApp.java | 15 ++++++++ .../config/MvcConfig.java | 38 +++++++++++++++++++ .../config/PageController.java | 14 +++++++ .../src/main/resources/messages.properties | 4 ++ .../src/main/resources/messages_fr.properties | 4 ++ .../resources/templates/international.html | 29 ++++++++++++++ 7 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/main/java/com/baeldung/internationalization/InternationalizationApp.java create mode 100644 spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java create mode 100644 spring-boot/src/main/java/com/baeldung/internationalization/config/PageController.java create mode 100644 spring-boot/src/main/resources/messages.properties create mode 100644 spring-boot/src/main/resources/messages_fr.properties create mode 100644 spring-boot/src/main/resources/templates/international.html diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 7a305322a6..f087617709 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -12,7 +12,7 @@ org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 1.5.2.RELEASE diff --git a/spring-boot/src/main/java/com/baeldung/internationalization/InternationalizationApp.java b/spring-boot/src/main/java/com/baeldung/internationalization/InternationalizationApp.java new file mode 100644 index 0000000000..c92d1c32e6 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/internationalization/InternationalizationApp.java @@ -0,0 +1,15 @@ +package com.baeldung.internationalization; + +import javax.annotation.security.RolesAllowed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class InternationalizationApp { + @RolesAllowed("*") + public static void main(String[] args) { + System.setProperty("security.basic.enabled", "false"); + SpringApplication.run(InternationalizationApp.class, args); + } +} diff --git a/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java b/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java new file mode 100644 index 0000000000..59f7fd3ba5 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java @@ -0,0 +1,38 @@ +package com.baeldung.internationalization.config; + +import java.util.Locale; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "com.baeldung.internationalization.config") +public class MvcConfig extends WebMvcConfigurerAdapter { + + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver slr = new SessionLocaleResolver(); + slr.setDefaultLocale(Locale.US); + return slr; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + lci.setParamName("lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } +} diff --git a/spring-boot/src/main/java/com/baeldung/internationalization/config/PageController.java b/spring-boot/src/main/java/com/baeldung/internationalization/config/PageController.java new file mode 100644 index 0000000000..96a534b853 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/internationalization/config/PageController.java @@ -0,0 +1,14 @@ +package com.baeldung.internationalization.config; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class PageController { + + @GetMapping("/international") + public String getInternationalPage() { + return "international"; + } + +} diff --git a/spring-boot/src/main/resources/messages.properties b/spring-boot/src/main/resources/messages.properties new file mode 100644 index 0000000000..e4dbc44c3f --- /dev/null +++ b/spring-boot/src/main/resources/messages.properties @@ -0,0 +1,4 @@ +greeting=Hello! Welcome to our website! +lang.change=Change the language +lang.eng=English +lang.fr=French \ No newline at end of file diff --git a/spring-boot/src/main/resources/messages_fr.properties b/spring-boot/src/main/resources/messages_fr.properties new file mode 100644 index 0000000000..ac5853717d --- /dev/null +++ b/spring-boot/src/main/resources/messages_fr.properties @@ -0,0 +1,4 @@ +greeting=Bonjour! Bienvenue sur notre site! +lang.change=Changez la langue +lang.eng=Anglais +lang.fr=Francais \ No newline at end of file diff --git a/spring-boot/src/main/resources/templates/international.html b/spring-boot/src/main/resources/templates/international.html new file mode 100644 index 0000000000..a2a5fbb591 --- /dev/null +++ b/spring-boot/src/main/resources/templates/international.html @@ -0,0 +1,29 @@ + + + + +Home + + + + +

+ +

+: + + + \ No newline at end of file From fbd5d1d2a81780c2d3eabd6ba75c3f4e7f759f14 Mon Sep 17 00:00:00 2001 From: Mohamed Sanaulla Date: Fri, 17 Mar 2017 10:36:27 +0300 Subject: [PATCH 120/291] code for Introduction to Project Jigsaw BAEL-603 (#1421) --- core-java-9/compile-modules.sh | 1 + core-java-9/compile-student-client.bat | 3 +++ core-java-9/compile-student-model.bat | 2 ++ .../compile-student-service-dbimpl.bat | 3 +++ core-java-9/compile-student-service.bat | 3 +++ core-java-9/run-student-client.bat | 1 + core-java-9/run-student-client.sh | 1 + .../student/client/StudentClient.java | 16 +++++++++++ .../module-info.java | 3 +++ .../com/baeldung/student/model/Student.java | 12 +++++++++ .../module-info.java | 3 +++ .../service/dbimpl/StudentDbService.java | 27 +++++++++++++++++++ .../module-info.java | 4 +++ .../student/service/StudentService.java | 14 ++++++++++ .../module-info.java | 4 +++ 15 files changed, 97 insertions(+) create mode 100644 core-java-9/compile-modules.sh create mode 100644 core-java-9/compile-student-client.bat create mode 100644 core-java-9/compile-student-model.bat create mode 100644 core-java-9/compile-student-service-dbimpl.bat create mode 100644 core-java-9/compile-student-service.bat create mode 100644 core-java-9/run-student-client.bat create mode 100644 core-java-9/run-student-client.sh create mode 100644 core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java create mode 100644 core-java-9/src/modules/com.baeldung.student.client/module-info.java create mode 100644 core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java create mode 100644 core-java-9/src/modules/com.baeldung.student.model/module-info.java create mode 100644 core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java create mode 100644 core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java create mode 100644 core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java create mode 100644 core-java-9/src/modules/com.baeldung.student.service/module-info.java diff --git a/core-java-9/compile-modules.sh b/core-java-9/compile-modules.sh new file mode 100644 index 0000000000..4c9521de75 --- /dev/null +++ b/core-java-9/compile-modules.sh @@ -0,0 +1 @@ +javac -d mods --module-source-path src/modules $(find src/modules -name "*.java") \ No newline at end of file diff --git a/core-java-9/compile-student-client.bat b/core-java-9/compile-student-client.bat new file mode 100644 index 0000000000..72b2774480 --- /dev/null +++ b/core-java-9/compile-student-client.bat @@ -0,0 +1,3 @@ +javac --module-path mods -d mods/com.baeldung.student.client^ + src/modules/com.baeldung.student.client/module-info.java^ + src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java \ No newline at end of file diff --git a/core-java-9/compile-student-model.bat b/core-java-9/compile-student-model.bat new file mode 100644 index 0000000000..902756c274 --- /dev/null +++ b/core-java-9/compile-student-model.bat @@ -0,0 +1,2 @@ +javac -d mods/com.baeldung.student.model src/modules/com.baeldung.student.model/module-info.java^ + src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java \ No newline at end of file diff --git a/core-java-9/compile-student-service-dbimpl.bat b/core-java-9/compile-student-service-dbimpl.bat new file mode 100644 index 0000000000..bd1cfb7cfe --- /dev/null +++ b/core-java-9/compile-student-service-dbimpl.bat @@ -0,0 +1,3 @@ +javac --module-path mods -d mods/com.baeldung.student.service.dbimpl^ + src/modules/com.baeldung.student.service.dbimpl/module-info.java^ + src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java \ No newline at end of file diff --git a/core-java-9/compile-student-service.bat b/core-java-9/compile-student-service.bat new file mode 100644 index 0000000000..2892b237d1 --- /dev/null +++ b/core-java-9/compile-student-service.bat @@ -0,0 +1,3 @@ +javac --module-path mods -d mods/com.baeldung.student.service^ + src/modules/com.baeldung.student.service/module-info.java^ + src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java \ No newline at end of file diff --git a/core-java-9/run-student-client.bat b/core-java-9/run-student-client.bat new file mode 100644 index 0000000000..2b78a26ec4 --- /dev/null +++ b/core-java-9/run-student-client.bat @@ -0,0 +1 @@ +java --module-path mods -m com.baeldung.student.client/com.baeldung.student.client.StudentClient \ No newline at end of file diff --git a/core-java-9/run-student-client.sh b/core-java-9/run-student-client.sh new file mode 100644 index 0000000000..2b78a26ec4 --- /dev/null +++ b/core-java-9/run-student-client.sh @@ -0,0 +1 @@ +java --module-path mods -m com.baeldung.student.client/com.baeldung.student.client.StudentClient \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java b/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java new file mode 100644 index 0000000000..b5b5d1eead --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java @@ -0,0 +1,16 @@ +package com.baeldung.student.client; + +import com.baeldung.student.service.StudentService; +import com.baeldung.student.service.dbimpl.StudentDbService; +import com.baeldung.student.model.Student; + +public class StudentClient{ + + public static void main(String[] args) { + StudentService service = new StudentDbService(); + service.create(new Student()); + service.read("17SS0001"); + service.update(new Student()); + service.delete("17SS0001"); + } +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.client/module-info.java b/core-java-9/src/modules/com.baeldung.student.client/module-info.java new file mode 100644 index 0000000000..3979297068 --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.client/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.student.client{ + requires com.baeldung.student.service.dbimpl; +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java b/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java new file mode 100644 index 0000000000..21c0b4e0ae --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java @@ -0,0 +1,12 @@ +package com.baeldung.student.model; + +import java.util.Date; + +public class Student{ + public String registrationId; + public String firstName; + public String lastName; + public Date dateOfBirth; + public String city; + public String country; +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.model/module-info.java b/core-java-9/src/modules/com.baeldung.student.model/module-info.java new file mode 100644 index 0000000000..6f60e3b4dc --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.model/module-info.java @@ -0,0 +1,3 @@ +module com.baeldung.student.model{ + exports com.baeldung.student.model; +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java new file mode 100644 index 0000000000..fb24a440f0 --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java @@ -0,0 +1,27 @@ +package com.baeldung.student.service.dbimpl; + +import com.baeldung.student.service.StudentService; +import com.baeldung.student.model.Student; + +public class StudentDbService implements StudentService{ + + public String create(Student student){ + System.out.println("Creating student in DB..."); + return student.registrationId; + } + + public Student read(String registrationId){ + System.out.println("Reading student from DB..."); + return new Student(); + } + + public Student update(Student student){ + System.out.println("Updating sutdent in DB..."); + return student; + } + + public String delete(String registrationId){ + System.out.println("Deleteing sutdent in DB..."); + return registrationId; + } +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java new file mode 100644 index 0000000000..a55b4e0f80 --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java @@ -0,0 +1,4 @@ +module com.baeldung.student.service.dbimpl{ + requires transitive com.baeldung.student.service; + exports com.baeldung.student.service.dbimpl; +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java b/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java new file mode 100644 index 0000000000..3c0070ff49 --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java @@ -0,0 +1,14 @@ +package com.baeldung.student.service; + +import com.baeldung.student.model.Student; + +public interface StudentService{ + + public String create(Student student); + + public Student read(String registrationId); + + public Student update(Student student); + + public String delete(String registrationId); +} \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service/module-info.java b/core-java-9/src/modules/com.baeldung.student.service/module-info.java new file mode 100644 index 0000000000..c083e62776 --- /dev/null +++ b/core-java-9/src/modules/com.baeldung.student.service/module-info.java @@ -0,0 +1,4 @@ +module com.baeldung.student.service{ + requires transitive com.baeldung.student.model; + exports com.baeldung.student.service; +} \ No newline at end of file From ac50687880e6bb3ee8c0b3d1bf210744147d4c9a Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Fri, 17 Mar 2017 08:19:37 -0500 Subject: [PATCH 121/291] README files for BAEL-393 and BAEL-541 (#1409) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files --- guice/README.md | 4 ++++ spring-security-mvc-boot/README.MD | 1 + 2 files changed, 5 insertions(+) create mode 100644 guice/README.md diff --git a/guice/README.md b/guice/README.md new file mode 100644 index 0000000000..d1bd1ff883 --- /dev/null +++ b/guice/README.md @@ -0,0 +1,4 @@ +## Google Guice Tutorials Project + +### Relevant Articles +- [Guide to Google Guice](http://www.baeldung.com/guice) diff --git a/spring-security-mvc-boot/README.MD b/spring-security-mvc-boot/README.MD index 3e789dedad..70b0f23cbb 100644 --- a/spring-security-mvc-boot/README.MD +++ b/spring-security-mvc-boot/README.MD @@ -6,3 +6,4 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com - [Custom AccessDecisionVoters in Spring Security](http://www.baeldung.com/spring-security-custom-voter) - [Spring Security: Authentication with a Database-backed UserDetailsService](http://www.baeldung.com/spring-security-authentication-with-a-database) - [Two Login Pages with Spring Security](http://www.baeldung.com/spring-security-two-login-pages) +- [Multiple Entry Points in Spring Security](http://www.baeldung.com/spring-security-multiple-entry-points) From e7e6326a0034fd40a5bc43ac5d35a00d5371cab7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Mar 2017 13:57:34 -0400 Subject: [PATCH 122/291] Spring MVC Custom Validator --- spring-mvc-java/pom.xml | 23 ++++++++++- .../ContactNumberConstraint.java | 22 ++++++++++ .../ContactNumberValidator.java | 19 +++++++++ .../com/baeldung/model/ValidatedPhone.java | 18 ++++++++ .../controller/ValidatedPhoneController.java | 35 ++++++++++++++++ .../src/main/webapp/WEB-INF/mvc-servlet.xml | 16 ++++++-- .../main/webapp/WEB-INF/view/phoneHome.jsp | 38 +++++++++++++++++ .../controller/CustomMVCValidatorTest.java | 41 +++++++++++++++++++ 8 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java create mode 100644 spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java create mode 100644 spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp create mode 100644 spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index ef18cef3e0..0f6dbfbd98 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -166,7 +166,28 @@ poi-ooxml ${poi.version} - + + + + javax.validation + validation-api + 1.1.0.Final + + + org.hibernate + hibernate-validator + 5.1.2.Final + + + javax.el + javax.el-api + 2.2.4 + + + org.glassfish.web + javax.el + 2.2.4 + diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java new file mode 100644 index 0000000000..2fba2720c3 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java @@ -0,0 +1,22 @@ +package com.baeldung.customvalidator; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Documented +@Constraint(validatedBy = ContactNumberValidator.class) +@Target( { ElementType.METHOD, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ContactNumberConstraint { + + String message() default "Invalid phone number"; + Class[] groups() default {}; + Class[] payload() default {}; + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java new file mode 100644 index 0000000000..a7eb7a9df4 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java @@ -0,0 +1,19 @@ +package com.baeldung.customvalidator; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class ContactNumberValidator implements ConstraintValidator { + + @Override + public void initialize(ContactNumberConstraint contactNumber) {} + + @Override + public boolean isValid(String contactField, ConstraintValidatorContext cxt) { + if(contactField == null) { + return false; + } + return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java new file mode 100644 index 0000000000..f860394707 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java @@ -0,0 +1,18 @@ +package com.baeldung.model; + +import com.baeldung.customvalidator.ContactNumberConstraint; + +public class ValidatedPhone { + + @ContactNumberConstraint + private String phone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + +} diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java new file mode 100644 index 0000000000..70b151e066 --- /dev/null +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java @@ -0,0 +1,35 @@ +package com.baeldung.web.controller; + +import javax.validation.Valid; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import com.baeldung.model.ValidatedPhone; + +@Controller +@EnableWebMvc +public class ValidatedPhoneController { + + @RequestMapping(value="/validatePhone", method=RequestMethod.GET) + public String loadFormPage(Model m) { + m.addAttribute("validatedPhone", new ValidatedPhone()); + return "phoneHome"; + } + + @RequestMapping(value="/addValidatePhone", method=RequestMethod.POST) + public String submitForm(@Valid ValidatedPhone validatedPhone, BindingResult result, Model m) { + if(result.hasErrors()) { + return "phoneHome"; + } + + m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + return "phoneHome"; + } + + +} diff --git a/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml b/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml index 4ba9642448..b0a4d4892a 100644 --- a/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml +++ b/spring-mvc-java/src/main/webapp/WEB-INF/mvc-servlet.xml @@ -1,6 +1,14 @@ - - + + + \ No newline at end of file diff --git a/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp b/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp new file mode 100644 index 0000000000..b873e9bc5f --- /dev/null +++ b/spring-mvc-java/src/main/webapp/WEB-INF/view/phoneHome.jsp @@ -0,0 +1,38 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> + + + + + Sample Form + + + + +
+ +

Phone Number

+
${message}
+ + + + + + +
+ + +
+
+ + diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java new file mode 100644 index 0000000000..069cc8e141 --- /dev/null +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/CustomMVCValidatorTest.java @@ -0,0 +1,41 @@ +package com.baeldung.web.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +public class CustomMVCValidatorTest { + + private MockMvc mockMvc; + + @Before + public void setup(){ + this.mockMvc = MockMvcBuilders.standaloneSetup(new ValidatedPhoneController()).build(); + } + + @Test + public void givenPhonePageUri_whenMockMvc_thenReturnsPhonePage() throws Exception{ + this.mockMvc.perform(get("/validatePhone")).andExpect(view().name("phoneHome")); + } + + @Test + public void givenPhoneURIWithPostAndFormData_whenMockMVC_thenVerifyErrorResponse() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.post("/addValidatePhone"). + accept(MediaType.TEXT_HTML). + param("phoneInput", "123")). + andExpect(model().attributeHasFieldErrorCode("validatedPhone", "phone","ContactNumberConstraint")). + andExpect(view().name("phoneHome")). + andExpect(status().isOk()). + andDo(print()); + } + +} From 99bebe806c3bd50eaddd5e1ab006c299ce4c9cfb Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 18 Mar 2017 07:05:02 +0100 Subject: [PATCH 123/291] Refactor flattening lists example (#1372) --- .../flattennestedlist/FlattenNestedList.java | 17 ----- .../FlattenNestedListTest.java | 76 +++++++++++-------- 2 files changed, 44 insertions(+), 49 deletions(-) delete mode 100644 core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java diff --git a/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java b/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java deleted file mode 100644 index 11ee66560b..0000000000 --- a/core-java/src/main/java/com/baeldung/list/flattennestedlist/FlattenNestedList.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.baeldung.list.flattennestedlist; - -import java.util.ArrayList; -import java.util.List; - -public class FlattenNestedList { - - public List flattenListOfLists(List> lol) { - - // flatten the list - List ls = new ArrayList<>(); - lol.forEach((k) -> ls.addAll(k)); - - return ls; - } - -} diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java index 09bfdae9a5..cf9334954b 100644 --- a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -1,52 +1,64 @@ package com.baeldung.list.flattennestedlist; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class FlattenNestedListTest { - private static final Logger LOGGER = LoggerFactory.getLogger(FlattenNestedListTest.class); - private FlattenNestedList flol; - - @Before - public void setup() { - flol = new FlattenNestedList(); - } - @Test - public void givenListOfListOfString_flattenNestedList() { - - // create the list to flatten + public void givenListOfListOfString_flattenNestedList1() { + // given List ls1 = Arrays.asList("one:one", "one:two", "one:three"); List ls2 = Arrays.asList("two:one", "two:two", "two:three"); List ls3 = Arrays.asList("three:one", "three:two", "three:three"); - List> lol = new ArrayList<>(); - lol.addAll(Arrays.asList(ls1, ls2, ls3)); - - // show nested list - LOGGER.debug("\nNested list: "); - lol.forEach((nl) -> LOGGER.debug(nl + "")); + List> list = Arrays.asList(ls1, ls2, ls3); - // flatten it - List ls = flol.flattenListOfLists(lol); + // when + List ls = flattenListOfListsImperatively(list); + // then assertNotNull(ls); assertTrue(ls.size() == 9); - - // show flattened list - LOGGER.debug("\nFlattened list:"); - ls.forEach((l) -> LOGGER.debug(l)); + //TODO content assertion + } + @Test + public void givenListOfListOfString_flattenNestedList2() { + // given + List ls1 = Arrays.asList("one:one", "one:two", "one:three"); + List ls2 = Arrays.asList("two:one", "two:two", "two:three"); + List ls3 = Arrays.asList("three:one", "three:two", "three:three"); + + List> list = Arrays.asList(ls1, ls2, ls3); + + // when + List ls = flattenListOfListsStream(list); + + // then + assertNotNull(ls); + assertTrue(ls.size() == 9); + //TODO content assertion + } + + public List flattenListOfListsImperatively(List> list) { + List ls = new ArrayList<>(); + list.forEach(ls::addAll); + return ls; + } + + public List flattenListOfListsStream(List> list) { + return list.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); } } From dc90aace68ccb29428970fde4283784c405ed1a6 Mon Sep 17 00:00:00 2001 From: Mohamed Sanaulla Date: Sat, 18 Mar 2017 10:18:04 +0300 Subject: [PATCH 124/291] incorporate few review comments for bael-603 (#1429) --- .../student/client/StudentClient.java | 16 ++++---- .../module-info.java | 2 +- .../com/baeldung/student/model/Student.java | 17 +++++---- .../module-info.java | 2 +- .../service/dbimpl/StudentDbService.java | 37 ++++++++++--------- .../module-info.java | 5 ++- .../student/service/StudentService.java | 10 ++--- .../module-info.java | 4 +- 8 files changed, 50 insertions(+), 43 deletions(-) diff --git a/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java b/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java index b5b5d1eead..e6fce9163f 100644 --- a/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java +++ b/core-java-9/src/modules/com.baeldung.student.client/com/baeldung/student/client/StudentClient.java @@ -4,13 +4,13 @@ import com.baeldung.student.service.StudentService; import com.baeldung.student.service.dbimpl.StudentDbService; import com.baeldung.student.model.Student; -public class StudentClient{ +public class StudentClient { - public static void main(String[] args) { - StudentService service = new StudentDbService(); - service.create(new Student()); - service.read("17SS0001"); - service.update(new Student()); - service.delete("17SS0001"); - } + public static void main(String[] args) { + StudentService service = new StudentDbService(); + service.create(new Student()); + service.read("17SS0001"); + service.update(new Student()); + service.delete("17SS0001"); + } } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.client/module-info.java b/core-java-9/src/modules/com.baeldung.student.client/module-info.java index 3979297068..7ef7b430fc 100644 --- a/core-java-9/src/modules/com.baeldung.student.client/module-info.java +++ b/core-java-9/src/modules/com.baeldung.student.client/module-info.java @@ -1,3 +1,3 @@ module com.baeldung.student.client{ - requires com.baeldung.student.service.dbimpl; + requires com.baeldung.student.service.dbimpl; } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java b/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java index 21c0b4e0ae..d7f8f69107 100644 --- a/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java +++ b/core-java-9/src/modules/com.baeldung.student.model/com/baeldung/student/model/Student.java @@ -2,11 +2,14 @@ package com.baeldung.student.model; import java.util.Date; -public class Student{ - public String registrationId; - public String firstName; - public String lastName; - public Date dateOfBirth; - public String city; - public String country; +public class Student { + private String registrationId; + + public String getRegistrationId() { + return registrationId; + } + + public void setRegistrationId(String registrationId) { + this.registrationId = registrationId; + } } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.model/module-info.java b/core-java-9/src/modules/com.baeldung.student.model/module-info.java index 6f60e3b4dc..3bdab058d4 100644 --- a/core-java-9/src/modules/com.baeldung.student.model/module-info.java +++ b/core-java-9/src/modules/com.baeldung.student.model/module-info.java @@ -1,3 +1,3 @@ module com.baeldung.student.model{ - exports com.baeldung.student.model; + exports com.baeldung.student.model; } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java index fb24a440f0..2519da085b 100644 --- a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java +++ b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/com/baeldung/student/service/dbimpl/StudentDbService.java @@ -2,26 +2,29 @@ package com.baeldung.student.service.dbimpl; import com.baeldung.student.service.StudentService; import com.baeldung.student.model.Student; +import java.util.logging.*; -public class StudentDbService implements StudentService{ +public class StudentDbService implements StudentService { - public String create(Student student){ - System.out.println("Creating student in DB..."); - return student.registrationId; - } + private static Logger logger = Logger.getLogger("StudentDbService"); - public Student read(String registrationId){ - System.out.println("Reading student from DB..."); - return new Student(); - } + public String create(Student student) { + logger.log(Level.INFO, "Creating student in DB..."); + return student.getRegistrationId(); + } - public Student update(Student student){ - System.out.println("Updating sutdent in DB..."); - return student; - } + public Student read(String registrationId) { + logger.log(Level.INFO, "Reading student from DB..."); + return new Student(); + } - public String delete(String registrationId){ - System.out.println("Deleteing sutdent in DB..."); - return registrationId; - } + public Student update(Student student) { + logger.log(Level.INFO, "Updating sutdent in DB..."); + return student; + } + + public String delete(String registrationId) { + logger.log(Level.INFO, "Deleteing sutdent in DB..."); + return registrationId; + } } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java index a55b4e0f80..96a453ea6b 100644 --- a/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java +++ b/core-java-9/src/modules/com.baeldung.student.service.dbimpl/module-info.java @@ -1,4 +1,5 @@ module com.baeldung.student.service.dbimpl{ - requires transitive com.baeldung.student.service; - exports com.baeldung.student.service.dbimpl; + requires transitive com.baeldung.student.service; + exports com.baeldung.student.service.dbimpl; + requires java.logging; } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java b/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java index 3c0070ff49..6076bf12e3 100644 --- a/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java +++ b/core-java-9/src/modules/com.baeldung.student.service/com/baeldung/student/service/StudentService.java @@ -2,13 +2,13 @@ package com.baeldung.student.service; import com.baeldung.student.model.Student; -public interface StudentService{ +public interface StudentService { - public String create(Student student); + public String create(Student student); - public Student read(String registrationId); + public Student read(String registrationId); - public Student update(Student student); + public Student update(Student student); - public String delete(String registrationId); + public String delete(String registrationId); } \ No newline at end of file diff --git a/core-java-9/src/modules/com.baeldung.student.service/module-info.java b/core-java-9/src/modules/com.baeldung.student.service/module-info.java index c083e62776..5de9e58348 100644 --- a/core-java-9/src/modules/com.baeldung.student.service/module-info.java +++ b/core-java-9/src/modules/com.baeldung.student.service/module-info.java @@ -1,4 +1,4 @@ module com.baeldung.student.service{ - requires transitive com.baeldung.student.model; - exports com.baeldung.student.service; + requires transitive com.baeldung.student.model; + exports com.baeldung.student.service; } \ No newline at end of file From 42f1ef0bf38782db75a00cfb5a7af678b490407a Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Sat, 18 Mar 2017 09:20:33 +0000 Subject: [PATCH 125/291] BAEL-112 - custom validator - format fixes --- .../ContactNumberConstraint.java | 6 +++-- .../ContactNumberValidator.java | 7 +++--- .../com/baeldung/model/ValidatedPhone.java | 6 ++++- .../controller/ValidatedPhoneController.java | 24 +++++++++---------- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java index 2fba2720c3..dbd38c1122 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberConstraint.java @@ -11,12 +11,14 @@ import javax.validation.Payload; @Documented @Constraint(validatedBy = ContactNumberValidator.class) -@Target( { ElementType.METHOD, ElementType.FIELD }) +@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface ContactNumberConstraint { String message() default "Invalid phone number"; + Class[] groups() default {}; + Class[] payload() default {}; - + } diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java index a7eb7a9df4..713b7429cf 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java @@ -6,14 +6,15 @@ import javax.validation.ConstraintValidatorContext; public class ContactNumberValidator implements ConstraintValidator { @Override - public void initialize(ContactNumberConstraint contactNumber) {} + public void initialize(ContactNumberConstraint contactNumber) { + } @Override public boolean isValid(String contactField, ConstraintValidatorContext cxt) { - if(contactField == null) { + if (contactField == null) { return false; } - return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); + return contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); } } diff --git a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java index f860394707..be702a8517 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java +++ b/spring-mvc-java/src/main/java/com/baeldung/model/ValidatedPhone.java @@ -3,7 +3,7 @@ package com.baeldung.model; import com.baeldung.customvalidator.ContactNumberConstraint; public class ValidatedPhone { - + @ContactNumberConstraint private String phone; @@ -15,4 +15,8 @@ public class ValidatedPhone { this.phone = phone; } + @Override + public String toString() { + return phone; + } } diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java index 70b151e066..54b0e19e60 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java @@ -15,21 +15,21 @@ import com.baeldung.model.ValidatedPhone; @EnableWebMvc public class ValidatedPhoneController { - @RequestMapping(value="/validatePhone", method=RequestMethod.GET) + @RequestMapping(value = "/validatePhone", method = RequestMethod.GET) public String loadFormPage(Model m) { - m.addAttribute("validatedPhone", new ValidatedPhone()); - return "phoneHome"; + m.addAttribute("validatedPhone", new ValidatedPhone()); + return "phoneHome"; } - - @RequestMapping(value="/addValidatePhone", method=RequestMethod.POST) + + @RequestMapping(value = "/addValidatePhone", method = RequestMethod.POST) public String submitForm(@Valid ValidatedPhone validatedPhone, BindingResult result, Model m) { - if(result.hasErrors()) { - return "phoneHome"; - } - - m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + if (result.hasErrors()) { return "phoneHome"; + } + + m.addAttribute("message", "Successfully saved phone: " + validatedPhone.toString()); + return "phoneHome"; } - - + + } From 6300112fc66ef339a1e1815e3d49bc9d851703e8 Mon Sep 17 00:00:00 2001 From: mariiakulik Date: Sat, 18 Mar 2017 20:25:06 +0100 Subject: [PATCH 126/291] README files update (#1435) * Create README.md * Update README.md * Update README.md * Create README.md * Update README.md * Update README.md * Update README.md * Create README.md * Update README.md * Create README.md * Update README.md * Create README.md * Update README.md * Update README.md * Create README.md * Create README.md * Update README.md * Update README.md * Update README.md * Create README.md * Create README.md * Update README.md * Update README.md * Update README.md * Update README.md * Create README.md * Update README.md * Update README.md * Update README.md * Update README.MD * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Create README.md * Create README.md * Update README.md * Create README.md * Update README.md * Update README.md * Create README.md * Create README.md * Update README.md * Update README.md * Update README.MD * Update README.MD * Create README.md --- Twitter4J/README.md | 3 +++ aws/README.md | 3 +++ axon/README.md | 3 +++ core-java-9/README.md | 5 ++++- core-java/README.md | 4 ++++ guava/README.md | 1 + hbase/README.md | 3 +++ java-websocket/README.md | 3 +++ jooq/README.md | 3 +++ kotlin/README.md | 1 + libraries/README.md | 11 ++++++++++- .../src/test/java/com/baeldung/cglib/proxy/README.md | 3 +++ log4j2/README.md | 3 +++ mesos-marathon/README.md | 3 +++ mockito2/README.md | 4 +++- protobuffer/README.md | 3 +++ rabbitmq/README.md | 3 +++ ratpack/README.md | 3 +++ reactor-core/README.md | 3 +++ redis/README.md | 1 + spring-boot/README.MD | 4 +++- spring-cloud/spring-cloud-bootstrap/README.MD | 2 ++ spring-hibernate5/README.md | 3 +++ spring-ldap/README.md | 5 ++++- spring-security-openid/README.md | 6 +++++- spring-security-stormpath/README.md | 3 +++ struts2/README.md | 3 +++ 27 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 Twitter4J/README.md create mode 100644 aws/README.md create mode 100644 axon/README.md create mode 100644 hbase/README.md create mode 100644 java-websocket/README.md create mode 100644 jooq/README.md create mode 100644 libraries/src/test/java/com/baeldung/cglib/proxy/README.md create mode 100644 log4j2/README.md create mode 100644 mesos-marathon/README.md create mode 100644 protobuffer/README.md create mode 100644 rabbitmq/README.md create mode 100644 ratpack/README.md create mode 100644 reactor-core/README.md create mode 100644 spring-hibernate5/README.md create mode 100644 spring-security-stormpath/README.md create mode 100644 struts2/README.md diff --git a/Twitter4J/README.md b/Twitter4J/README.md new file mode 100644 index 0000000000..3057c1c4b2 --- /dev/null +++ b/Twitter4J/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Twitter4J](http://www.baeldung.com/twitter4j) diff --git a/aws/README.md b/aws/README.md new file mode 100644 index 0000000000..10db004765 --- /dev/null +++ b/aws/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [AWS Lambda Using DynamoDB With Java](http://www.baeldung.com/aws-lambda-dynamodb-java) diff --git a/axon/README.md b/axon/README.md new file mode 100644 index 0000000000..f1ae5d00d8 --- /dev/null +++ b/axon/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [A Guide to the Axon Framework](http://www.baeldung.com/axon-cqrs-event-sourcing) diff --git a/core-java-9/README.md b/core-java-9/README.md index 6e58383a5e..a6cda8e883 100644 --- a/core-java-9/README.md +++ b/core-java-9/README.md @@ -8,4 +8,7 @@ - [Java 9 Stream API Improvements](http://www.baeldung.com/java-9-stream-api) - [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods) - [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors) -- [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java9-completablefuture-api-improvements/) \ No newline at end of file +- [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java9-completablefuture-api-improvements/) +- [Spring Security – Redirect to the Previous URL After Login](http://www.baeldung.com/spring-security-redirect-login) +- [Java 9 Process API Improvements](http://www.baeldung.com/java-9-process-api) +- [Introduction to Java 9 StackWalking API](http://www.baeldung.com/java-9-stackwalking-api) diff --git a/core-java/README.md b/core-java/README.md index a34908d8ae..3cdc8c2290 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -79,3 +79,7 @@ - [The Java HashMap Under the Hood](http://www.baeldung.com/java-hashmap) - [A Guide to LinkedHashMap in Java](http://www.baeldung.com/java-linked-hashmap) - [A Guide to TreeMap in Java](http://www.baeldung.com/java-treemap) +- [Finding Max/Min of a List or Collection](http://www.baeldung.com/java-collection-min-max) +- [Guide to java.util.concurrent.Locks](http://www.baeldung.com/java-concurrent-locks) +- [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) +- [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) diff --git a/guava/README.md b/guava/README.md index ee224bae5f..f46c4dd3de 100644 --- a/guava/README.md +++ b/guava/README.md @@ -24,3 +24,4 @@ - [Guide to Guava RangeSet](http://www.baeldung.com/guava-rangeset) - [Guide to Guava RangeMap](http://www.baeldung.com/guava-rangemap) - [Guide to Guava Table](http://www.baeldung.com/guava-table) +- [Guide to Guava’s Reflection Utilities](http://www.baeldung.com/guava-reflection) diff --git a/hbase/README.md b/hbase/README.md new file mode 100644 index 0000000000..df2683b27a --- /dev/null +++ b/hbase/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [HBase with Java](http://www.baeldung.com/hbase) diff --git a/java-websocket/README.md b/java-websocket/README.md new file mode 100644 index 0000000000..f9f0784043 --- /dev/null +++ b/java-websocket/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [A Guide to the Java API for WebSocket](http://www.baeldung.com/java-websockets) diff --git a/jooq/README.md b/jooq/README.md new file mode 100644 index 0000000000..2f09cab46b --- /dev/null +++ b/jooq/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to jOOL](http://www.baeldung.com/jool) diff --git a/kotlin/README.md b/kotlin/README.md index 6447a26f5c..ceebde4573 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -1,3 +1,4 @@ ## Relevant articles: - [Introduction to the Kotlin Language](http://www.baeldung.com/kotlin) +- [A guide to the “when{}†block in Kotlin](http://www.baeldung.com/kotlin-when) diff --git a/libraries/README.md b/libraries/README.md index 7b4f7c36ac..a8ecf56cc2 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -1,5 +1,14 @@ +### Relevant articles + +- [Intro to Jasypt](http://www.baeldung.com/jasypt) +- [Array Processing with Apache Commons Lang 3](http://www.baeldung.com/array-processing-commons-lang) +- [String Processing with Apache Commons Lang 3](http://www.baeldung.com/string-processing-commons-lang) +- [Introduction to Javatuples](http://www.baeldung.com/java-tuples) +- [Introduction to Javassist](http://www.baeldung.com/javassist) + + The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own. The code examples related to different libraries should go in a new package. -Remember, for advanced libraries like JUnit, Jackson, etc. we already have separate modules. Please make sure to have a look at the existing modules in such cases. \ No newline at end of file +Remember, for advanced libraries like JUnit, Jackson, etc. we already have separate modules. Please make sure to have a look at the existing modules in such cases. diff --git a/libraries/src/test/java/com/baeldung/cglib/proxy/README.md b/libraries/src/test/java/com/baeldung/cglib/proxy/README.md new file mode 100644 index 0000000000..abeabc6162 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/cglib/proxy/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to cglib](http://www.baeldung.com/cglib) diff --git a/log4j2/README.md b/log4j2/README.md new file mode 100644 index 0000000000..3afd842c82 --- /dev/null +++ b/log4j2/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Intro to Log4j2 – Appenders, Layouts and Filters](http://www.baeldung.com/log4j2-appenders-layouts-filters) diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md new file mode 100644 index 0000000000..3223eb2478 --- /dev/null +++ b/mesos-marathon/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) diff --git a/mockito2/README.md b/mockito2/README.md index 587f1341bb..49741c66d1 100644 --- a/mockito2/README.md +++ b/mockito2/README.md @@ -1,4 +1,6 @@ -========= +### Relevant articles + +- [Mockito’s Java 8 Features](http://www.baeldung.com/mockito-2-java-8) ## Mockito 2 and Java 8 Tips diff --git a/protobuffer/README.md b/protobuffer/README.md new file mode 100644 index 0000000000..4dcdb3cf52 --- /dev/null +++ b/protobuffer/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Google Protocol Buffer](http://www.baeldung.com/google-protocol-buffer) diff --git a/rabbitmq/README.md b/rabbitmq/README.md new file mode 100644 index 0000000000..11300b047f --- /dev/null +++ b/rabbitmq/README.md @@ -0,0 +1,3 @@ +### Relevant articles +- [Introduction to RabbitMQ](http://www.baeldung.com/rabbitmq) + diff --git a/ratpack/README.md b/ratpack/README.md new file mode 100644 index 0000000000..af473ef0e8 --- /dev/null +++ b/ratpack/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Ratpack](http://www.baeldung.com/ratpack) diff --git a/reactor-core/README.md b/reactor-core/README.md new file mode 100644 index 0000000000..9d952ec84c --- /dev/null +++ b/reactor-core/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Intro To Reactor Core](http://www.baeldung.com/reactor-core) diff --git a/redis/README.md b/redis/README.md index 3ce9031b62..d179b80c33 100644 --- a/redis/README.md +++ b/redis/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Intro to Jedis – the Java Redis Client Library](http://www.baeldung.com/jedis-java-redis-client-library) +- [A Guide to Redis with Redisson](http://www.baeldung.com/redis-redisson) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 9fe18aaacc..4c078a5d38 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -1,7 +1,8 @@ ###The Course The "REST With Spring" Classes: http://bit.ly/restwithspring -###Relevant Articles: +### Relevant Articles: + - [Quick Guide to @RestClientTest in Spring Boot](http://www.baeldung.com/restclienttest-in-spring-boot) - [Intro to Spring Boot Starters](http://www.baeldung.com/spring-boot-starters) - [A Guide to Spring in Eclipse STS](http://www.baeldung.com/eclipse-sts-spring) @@ -11,3 +12,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Custom Data Binder in Spring MVC](http://www.baeldung.com/spring-mvc-custom-data-binder) - [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) - [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) +- [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) diff --git a/spring-cloud/spring-cloud-bootstrap/README.MD b/spring-cloud/spring-cloud-bootstrap/README.MD index 251c861830..d8eedc3249 100644 --- a/spring-cloud/spring-cloud-bootstrap/README.MD +++ b/spring-cloud/spring-cloud-bootstrap/README.MD @@ -1,6 +1,8 @@ ### Relevant Articles: - [Spring Cloud – Bootstrapping](http://www.baeldung.com/spring-cloud-bootstrapping) - [Spring Cloud – Securing Services](http://www.baeldung.com/spring-cloud-securing-services) +- [Spring Cloud – Tracing Services with Zipkin](http://www.baeldung.com/tracing-services-with-zipkin) + - To run the project: - copy the appliction-config folder to c:\Users\{username}\ on Windows or /Users/{username}/ on *nix. Then open a git bash terminal in application-config and run: diff --git a/spring-hibernate5/README.md b/spring-hibernate5/README.md new file mode 100644 index 0000000000..fd539fdcb6 --- /dev/null +++ b/spring-hibernate5/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Guide to @Immutable Annotation in Hibernate](http://www.baeldung.com/hibernate-immutable) diff --git a/spring-ldap/README.md b/spring-ldap/README.md index 56ffdee617..8dffadb685 100644 --- a/spring-ldap/README.md +++ b/spring-ldap/README.md @@ -1,4 +1,7 @@ -========= +### Relevant articles + +- [Spring LDAP Overview](http://www.baeldung.com/spring-ldap) + ## Spring LDAP Example Project - (http://www.baeldung.com/spring-ldap-overview/) diff --git a/spring-security-openid/README.md b/spring-security-openid/README.md index 79bf44f374..8c65c09f2f 100644 --- a/spring-security-openid/README.md +++ b/spring-security-openid/README.md @@ -1,4 +1,7 @@ -========= +### Relevant articles + +- [Spring Security and OpenID Connect](http://www.baeldung.com/spring-security-openid-connect) + ## OpenID Connect with Spring Security @@ -13,3 +16,4 @@ mvn spring-boot:run - Make sure you set redirect URI to http://localhost:8081/google-login - Once you have your client id and secret, make sure you add them to the `application.properties` of the project + diff --git a/spring-security-stormpath/README.md b/spring-security-stormpath/README.md new file mode 100644 index 0000000000..f83882112f --- /dev/null +++ b/spring-security-stormpath/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Spring Security with Stormpath](http://www.baeldung.com/spring-security-stormpath) diff --git a/struts2/README.md b/struts2/README.md new file mode 100644 index 0000000000..8a1425ccb5 --- /dev/null +++ b/struts2/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [A Quick Struts 2 Intro](http://www.baeldung.com/struts-2-intro) From 8981008cba13bd614d1dfea35805a7bc757c2149 Mon Sep 17 00:00:00 2001 From: mariiakulik Date: Sat, 18 Mar 2017 22:38:31 +0100 Subject: [PATCH 127/291] Update README.md (#1432) --- core-java/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core-java/README.md b/core-java/README.md index 3cdc8c2290..63e3748ec6 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -79,7 +79,9 @@ - [The Java HashMap Under the Hood](http://www.baeldung.com/java-hashmap) - [A Guide to LinkedHashMap in Java](http://www.baeldung.com/java-linked-hashmap) - [A Guide to TreeMap in Java](http://www.baeldung.com/java-treemap) +- [A Quick JUnit vs TestNG Comparison](http://www.baeldung.com/junit-vs-testng) - [Finding Max/Min of a List or Collection](http://www.baeldung.com/java-collection-min-max) - [Guide to java.util.concurrent.Locks](http://www.baeldung.com/java-concurrent-locks) - [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) - [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) + From 11536181b5f6d5ba0060559434c314cf85f5a5e4 Mon Sep 17 00:00:00 2001 From: mariiakulik Date: Sun, 19 Mar 2017 01:05:04 +0100 Subject: [PATCH 128/291] Update README.MD (#1433) --- spring-boot/README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 4c078a5d38..d70e83525b 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -12,4 +12,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [A Custom Data Binder in Spring MVC](http://www.baeldung.com/spring-mvc-custom-data-binder) - [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) - [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) +- [Guide to Spring WebUtils and ServletRequestUtils](http://www.baeldung.com/spring-webutils-servletrequestutils) - [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) + From ae6514b5cf0f32b4a6d948e947861eaa1b251825 Mon Sep 17 00:00:00 2001 From: mujahid Date: Sun, 19 Mar 2017 15:22:06 +0800 Subject: [PATCH 129/291] BAEL-347 Fixes (#1361) * solr-fulltext-search module created * solr-fulltext-search modue created * solr-fulltext-search change s * pom changes merged from upstream * removed integration tests from mvn build * Refactoring test class * removed test profile --- solr-fulltext-search/pom.xml | 34 -- .../service/ItemSearchServiceLiveTest.java | 374 ++++++++++++++++++ 2 files changed, 374 insertions(+), 34 deletions(-) create mode 100644 solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java diff --git a/solr-fulltext-search/pom.xml b/solr-fulltext-search/pom.xml index bed6afd48f..5b2950d64c 100644 --- a/solr-fulltext-search/pom.xml +++ b/solr-fulltext-search/pom.xml @@ -53,38 +53,4 @@
- - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - \ No newline at end of file diff --git a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java b/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java new file mode 100644 index 0000000000..1489d40787 --- /dev/null +++ b/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java @@ -0,0 +1,374 @@ +package com.baeldung.solr.fulltext.search.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.List; +import java.util.Map; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.response.FacetField.Count; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.response.RangeFacet; +import org.apache.solr.client.solrj.response.SpellCheckResponse; +import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; +import org.apache.solr.client.solrj.response.SuggesterResponse; +import org.apache.solr.common.SolrDocument; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.baeldung.solr.fulltext.search.model.Item; + +public class ItemSearchServiceLiveTest { + + private static SolrClient solrClient; + private static ItemSearchService itemSearchService; + private static final String solrUrl = "http://localhost:8987/solr/item"; + + @BeforeClass + public static void initBeans() throws Exception { + solrClient = new HttpSolrClient.Builder(solrUrl).build(); + itemSearchService = new ItemSearchServiceImpl(solrClient); + + solrClient.commit(); + } + + @Before + public void clearSolrData() throws Exception { + solrClient.deleteByQuery("*:*"); + } + + @Test + public void whenIndexing_thenAvailableOnRetrieval() throws Exception { + itemSearchService.index("hm0001", "Washing Machine", "Home Appliances", 450f); + final SolrDocument indexedDoc = solrClient.getById("hm0001"); + assertEquals("hm0001", indexedDoc.get("id")); + } + + @Test + public void whenIndexingBean_thenAvailableOnRetrieval() throws Exception { + Item item = new Item(); + item.setId("hm0002"); + item.setCategory("Televisions"); + item.setDescription("LED TV 32"); + item.setPrice(500); + itemSearchService.indexBean(item); + } + + @Test + public void whenSearchingByBasicQuery_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("brand1"); + query.setStart(0); + query.setRows(10); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + + } + + @Test + public void whenSearchingWithWildCard_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*rand?"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + } + + @Test + public void whenSearchingWithLogicalOperators_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 LED TV 32", "Washing Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("brand1 AND (Washing OR Refrigerator)"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFields_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("0003", "Brand2 LED TV 32", "Brand1 Washing Home Appliances", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("description:Brand* AND category:*Washing*"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingWithPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("washing MachIne"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithRealPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("\"washing machine\""); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingPhraseWithProximity_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("\"Washing equipment\"~2"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(1, items.size()); + } + + @Test + public void whenSearchingWithPriceRange_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:[100 TO 300]"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(3, items.size()); + } + + @Test + public void whenSearchingWithPriceRangeInclusiveExclusive_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:{100 TO 300]"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFilterQuery_thenAllMatchingItemsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("price:[100 TO 300]"); + query.addFilterQuery("description:Brand1", "category:Home Appliances"); + + QueryResponse response = solrClient.query(query); + List items = response.getBeans(Item.class); + + assertEquals(2, items.size()); + } + + @Test + public void whenSearchingWithFacetFields_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + query.addFacetField("category"); + + QueryResponse response = solrClient.query(query); + List facetResults = response.getFacetField("category").getValues(); + + assertEquals(2, facetResults.size()); + + for (Count count : facetResults) { + if ("categorya".equalsIgnoreCase(count.getName())) { + assertEquals(2, count.getCount()); + } else if ("categoryb".equalsIgnoreCase(count.getName())) { + assertEquals(2, count.getCount()); + } else { + fail("unexpected category"); + } + } + } + + @Test + public void whenSearchingWithFacetQuery_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + + query.addFacetQuery("Washing OR Refrigerator"); + query.addFacetQuery("Brand2"); + + QueryResponse response = solrClient.query(query); + Map facetQueryMap = response.getFacetQuery(); + + assertEquals(2, facetQueryMap.size()); + + for (Map.Entry entry : facetQueryMap.entrySet()) { + String facetQuery = entry.getKey(); + + if ("Washing OR Refrigerator".equals(facetQuery)) { + assertEquals(Integer.valueOf(2), entry.getValue()); + } else if ("Brand2".equals(facetQuery)) { + assertEquals(Integer.valueOf(2), entry.getValue()); + } else { + fail("unexpected query"); + } + + } + } + + @Test + public void whenSearchingWithFacetRange_thenAllMatchingFacetsShouldAvialble() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 125f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 150f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + + query.addNumericRangeFacet("price", 100, 275, 25); + + QueryResponse response = solrClient.query(query); + List rangeFacets = response.getFacetRanges().get(0).getCounts(); + + assertEquals(7, rangeFacets.size()); + } + + @Test + public void whenSearchingWithHitHighlighting_thenKeywordsShouldBeHighlighted() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("Appliances"); + query.setHighlight(true); + query.addHighlightField("category"); + query.setHighlightSimplePre(""); + query.setHighlightSimplePost(""); + QueryResponse response = solrClient.query(query); + + Map>> hitHighlightedMap = response.getHighlighting(); + Map> highlightedFieldMap = hitHighlightedMap.get("hm0001"); + List highlightedList = highlightedFieldMap.get("category"); + String highLightedText = highlightedList.get(0); + + assertEquals("Home Appliances", highLightedText); + + } + + @Test + public void whenSearchingWithKeywordWithMistake_thenSpellingSuggestionsShouldBeReturned() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setQuery("hme"); + query.set("spellcheck", "on"); + QueryResponse response = solrClient.query(query); + + SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse(); + + assertEquals(false, spellCheckResponse.isCorrectlySpelled()); + + Suggestion suggestion = spellCheckResponse.getSuggestions().get(0); + + assertEquals("hme", suggestion.getToken()); + + List alternatives = suggestion.getAlternatives(); + String alternative = alternatives.get(0); + + assertEquals("home", alternative); + } + + @Test + public void whenSearchingWithIncompleteKeyword_thenKeywordSuggestionsShouldBeReturned() throws Exception { + itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); + itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); + itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); + itemSearchService.index("hm0004", "Brand2 Dishwasher", "Home washing equipments", 250f); + + SolrQuery query = new SolrQuery(); + query.setRequestHandler("/suggest"); + query.set("suggest", "true"); + query.set("suggest.build", "true"); + query.set("suggest.dictionary", "mySuggester"); + query.set("suggest.q", "Hom"); + QueryResponse response = solrClient.query(query); + + SuggesterResponse suggesterResponse = response.getSuggesterResponse(); + Map> suggestedTerms = suggesterResponse.getSuggestedTerms(); + List suggestions = suggestedTerms.get("mySuggester"); + + assertEquals(2, suggestions.size()); + + for (String term : suggestions) { + if (!"Home Appliances".equals(term) && !"Home washing equipments".equals(term)) { + fail("Unexpected suggestions"); + } + } + + } + +} From 22b5c4924b175b4e0971f816a1dab74c6f3fb729 Mon Sep 17 00:00:00 2001 From: mariiakulik Date: Sun, 19 Mar 2017 08:33:49 +0100 Subject: [PATCH 130/291] Create README.md (#1434) --- spring-5/src/test/java/com/baeldung/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 spring-5/src/test/java/com/baeldung/README.md diff --git a/spring-5/src/test/java/com/baeldung/README.md b/spring-5/src/test/java/com/baeldung/README.md new file mode 100644 index 0000000000..f7b358ec3e --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Concurrent Test Execution in Spring 5](http://www.baeldung.com/spring-5-concurrent-tests) From 9d0cb1e2aa674f6974f261b62c020f52b44aba9b Mon Sep 17 00:00:00 2001 From: Yasin Date: Sun, 19 Mar 2017 14:21:25 +0530 Subject: [PATCH 131/291] BAEL-722 Intro to JSONassert (#1437) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements * BAEL-718 Quick intro to javatuples * merging pom from master * BAEL-722 Intro to JSONassert --- .../algorithms/ga/dijkstra/Dijkstra.java | 114 +++++++------- .../algorithms/ga/dijkstra/Graph.java | 42 ++--- .../baeldung/algorithms/ga/dijkstra/Node.java | 116 +++++++------- core-java/0.004102810554955205 | 0 core-java/0.04832801936270381 | 0 core-java/0.5633433244738808 | 0 core-java/0.6256429734439612 | 0 core-java/0.8260098203820962 | 0 core-java/0.9799201796740292 | 0 .../java/com/baeldung/examples/RunGuice.java | 64 ++++---- .../examples/guice/Communication.java | 80 +++++----- .../examples/guice/CommunicationMode.java | 24 +-- .../examples/guice/DefaultCommunicator.java | 102 ++++++------ .../guice/EmailCommunicationMode.java | 48 +++--- .../examples/guice/IMCommunicationMode.java | 60 +++---- .../examples/guice/SMSCommunicationMode.java | 60 +++---- .../examples/guice/aop/MessageLogger.java | 48 +++--- .../guice/aop/MessageSentLoggable.java | 34 ++-- .../examples/guice/binding/AOPModule.java | 46 +++--- .../examples/guice/binding/BasicModule.java | 74 ++++----- .../guice/constant/CommunicationModel.java | 34 ++-- .../examples/guice/marker/Communicator.java | 28 ++-- .../examples/guice/modules/BasicModule.java | 76 ++++----- .../javaeeannotations/LogInFilter.java | 72 ++++----- libraries/pom.xml | 148 +++++++++--------- .../baeldung/jsonassert/JsonAssertTest.java | 115 ++++++++++++++ xml/src/main/resources/customer-binding.xml | 0 27 files changed, 753 insertions(+), 632 deletions(-) delete mode 100644 core-java/0.004102810554955205 delete mode 100644 core-java/0.04832801936270381 delete mode 100644 core-java/0.5633433244738808 delete mode 100644 core-java/0.6256429734439612 delete mode 100644 core-java/0.8260098203820962 delete mode 100644 core-java/0.9799201796740292 create mode 100644 libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java mode change 100755 => 100644 xml/src/main/resources/customer-binding.xml diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java index 046f13983d..0b01e9b48b 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Dijkstra.java @@ -1,57 +1,57 @@ -package com.baeldung.algorithms.ga.dijkstra; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map.Entry; -import java.util.Set; - -public class Dijkstra { - - public static Graph calculateShortestPathFromSource(Graph graph, Node source) { - - source.setDistance(0); - - Set settledNodes = new HashSet<>(); - Set unsettledNodes = new HashSet<>(); - unsettledNodes.add(source); - - while (unsettledNodes.size() != 0) { - Node currentNode = getLowestDistanceNode(unsettledNodes); - unsettledNodes.remove(currentNode); - for (Entry adjacencyPair : currentNode.getAdjacentNodes().entrySet()) { - Node adjacentNode = adjacencyPair.getKey(); - Integer edgeWeigh = adjacencyPair.getValue(); - - if (!settledNodes.contains(adjacentNode)) { - CalculateMinimumDistance(adjacentNode, edgeWeigh, currentNode); - unsettledNodes.add(adjacentNode); - } - } - settledNodes.add(currentNode); - } - return graph; - } - - private static void CalculateMinimumDistance(Node evaluationNode, Integer edgeWeigh, Node sourceNode) { - Integer sourceDistance = sourceNode.getDistance(); - if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) { - evaluationNode.setDistance(sourceDistance + edgeWeigh); - LinkedList shortestPath = new LinkedList<>(sourceNode.getShortestPath()); - shortestPath.add(sourceNode); - evaluationNode.setShortestPath(shortestPath); - } - } - - private static Node getLowestDistanceNode(Set unsettledNodes) { - Node lowestDistanceNode = null; - int lowestDistance = Integer.MAX_VALUE; - for (Node node : unsettledNodes) { - int nodeDistance = node.getDistance(); - if (nodeDistance < lowestDistance) { - lowestDistance = nodeDistance; - lowestDistanceNode = node; - } - } - return lowestDistanceNode; - } -} +package com.baeldung.algorithms.ga.dijkstra; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map.Entry; +import java.util.Set; + +public class Dijkstra { + + public static Graph calculateShortestPathFromSource(Graph graph, Node source) { + + source.setDistance(0); + + Set settledNodes = new HashSet<>(); + Set unsettledNodes = new HashSet<>(); + unsettledNodes.add(source); + + while (unsettledNodes.size() != 0) { + Node currentNode = getLowestDistanceNode(unsettledNodes); + unsettledNodes.remove(currentNode); + for (Entry adjacencyPair : currentNode.getAdjacentNodes().entrySet()) { + Node adjacentNode = adjacencyPair.getKey(); + Integer edgeWeigh = adjacencyPair.getValue(); + + if (!settledNodes.contains(adjacentNode)) { + CalculateMinimumDistance(adjacentNode, edgeWeigh, currentNode); + unsettledNodes.add(adjacentNode); + } + } + settledNodes.add(currentNode); + } + return graph; + } + + private static void CalculateMinimumDistance(Node evaluationNode, Integer edgeWeigh, Node sourceNode) { + Integer sourceDistance = sourceNode.getDistance(); + if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) { + evaluationNode.setDistance(sourceDistance + edgeWeigh); + LinkedList shortestPath = new LinkedList<>(sourceNode.getShortestPath()); + shortestPath.add(sourceNode); + evaluationNode.setShortestPath(shortestPath); + } + } + + private static Node getLowestDistanceNode(Set unsettledNodes) { + Node lowestDistanceNode = null; + int lowestDistance = Integer.MAX_VALUE; + for (Node node : unsettledNodes) { + int nodeDistance = node.getDistance(); + if (nodeDistance < lowestDistance) { + lowestDistance = nodeDistance; + lowestDistanceNode = node; + } + } + return lowestDistanceNode; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java index 00db4b01e4..76694ed76e 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Graph.java @@ -1,21 +1,21 @@ -package com.baeldung.algorithms.ga.dijkstra; - -import java.util.HashSet; -import java.util.Set; - -public class Graph { - - private Set nodes = new HashSet<>(); - - public void addNode(Node nodeA) { - nodes.add(nodeA); - } - - public Set getNodes() { - return nodes; - } - - public void setNodes(Set nodes) { - this.nodes = nodes; - } -} +package com.baeldung.algorithms.ga.dijkstra; + +import java.util.HashSet; +import java.util.Set; + +public class Graph { + + private Set nodes = new HashSet<>(); + + public void addNode(Node nodeA) { + nodes.add(nodeA); + } + + public Set getNodes() { + return nodes; + } + + public void setNodes(Set nodes) { + this.nodes = nodes; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java index 256f12e204..ac34bfadd1 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/dijkstra/Node.java @@ -1,58 +1,58 @@ -package com.baeldung.algorithms.ga.dijkstra; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class Node { - - private String name; - - private LinkedList shortestPath = new LinkedList<>(); - - private Integer distance = Integer.MAX_VALUE; - - private Map adjacentNodes = new HashMap<>(); - - public Node(String name) { - this.name = name; - } - - public void addDestination(Node destination, int distance) { - adjacentNodes.put(destination, distance); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Map getAdjacentNodes() { - return adjacentNodes; - } - - public void setAdjacentNodes(Map adjacentNodes) { - this.adjacentNodes = adjacentNodes; - } - - public Integer getDistance() { - return distance; - } - - public void setDistance(Integer distance) { - this.distance = distance; - } - - public List getShortestPath() { - return shortestPath; - } - - public void setShortestPath(LinkedList shortestPath) { - this.shortestPath = shortestPath; - } - -} +package com.baeldung.algorithms.ga.dijkstra; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class Node { + + private String name; + + private LinkedList shortestPath = new LinkedList<>(); + + private Integer distance = Integer.MAX_VALUE; + + private Map adjacentNodes = new HashMap<>(); + + public Node(String name) { + this.name = name; + } + + public void addDestination(Node destination, int distance) { + adjacentNodes.put(destination, distance); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getAdjacentNodes() { + return adjacentNodes; + } + + public void setAdjacentNodes(Map adjacentNodes) { + this.adjacentNodes = adjacentNodes; + } + + public Integer getDistance() { + return distance; + } + + public void setDistance(Integer distance) { + this.distance = distance; + } + + public List getShortestPath() { + return shortestPath; + } + + public void setShortestPath(LinkedList shortestPath) { + this.shortestPath = shortestPath; + } + +} diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.8260098203820962 b/core-java/0.8260098203820962 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/guice/src/main/java/com/baeldung/examples/RunGuice.java b/guice/src/main/java/com/baeldung/examples/RunGuice.java index a07447cde8..660952f325 100644 --- a/guice/src/main/java/com/baeldung/examples/RunGuice.java +++ b/guice/src/main/java/com/baeldung/examples/RunGuice.java @@ -1,32 +1,32 @@ - -package com.baeldung.examples; - -import com.baeldung.examples.guice.Communication; -import com.baeldung.examples.guice.binding.AOPModule; -import com.baeldung.examples.guice.modules.BasicModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import java.util.Scanner; - -/** - * - * @author baeldung - */ -public class RunGuice { - - public static void main(String[] args) { - Injector injector = Guice.createInjector(new BasicModule(), new AOPModule()); - Communication comms = injector.getInstance(Communication.class); - Scanner scanner = new Scanner(System.in); - while (true) { - String input = scanner.nextLine(); - if (input.equalsIgnoreCase("q")) { - System.exit(0); - } else { - comms.sendMessage(input); - } - - } - - } -} + +package com.baeldung.examples; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.binding.AOPModule; +import com.baeldung.examples.guice.modules.BasicModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import java.util.Scanner; + +/** + * + * @author baeldung + */ +public class RunGuice { + + public static void main(String[] args) { + Injector injector = Guice.createInjector(new BasicModule(), new AOPModule()); + Communication comms = injector.getInstance(Communication.class); + Scanner scanner = new Scanner(System.in); + while (true) { + String input = scanner.nextLine(); + if (input.equalsIgnoreCase("q")) { + System.exit(0); + } else { + comms.sendMessage(input); + } + + } + + } +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/Communication.java b/guice/src/main/java/com/baeldung/examples/guice/Communication.java index 7f7cb822d8..464e0c641d 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/Communication.java +++ b/guice/src/main/java/com/baeldung/examples/guice/Communication.java @@ -1,40 +1,40 @@ - -package com.baeldung.examples.guice; - -import com.google.inject.Inject; -import com.google.inject.name.Named; -import java.util.Date; -import java.util.LinkedList; -import java.util.Queue; -import java.util.logging.Logger; - -/** - * - * @author baeldung - */ -public class Communication { - - final Date start = new Date(); - - @Inject - private Logger logger; - - @Inject - private DefaultCommunicator communicator; - - public Communication(Boolean keepRecords) { - if (keepRecords) { - System.out.println("keeping records"); - } - } - - public boolean sendMessage(String message) { - - return communicator.sendMessage(message); - } - - public DefaultCommunicator getCommunicator() { - return this.communicator; - } - -} + +package com.baeldung.examples.guice; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import java.util.Date; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Logger; + +/** + * + * @author baeldung + */ +public class Communication { + + final Date start = new Date(); + + @Inject + private Logger logger; + + @Inject + private DefaultCommunicator communicator; + + public Communication(Boolean keepRecords) { + if (keepRecords) { + System.out.println("keeping records"); + } + } + + public boolean sendMessage(String message) { + + return communicator.sendMessage(message); + } + + public DefaultCommunicator getCommunicator() { + return this.communicator; + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java index 444b775478..7a36f0c276 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/CommunicationMode.java @@ -1,12 +1,12 @@ - -package com.baeldung.examples.guice; - -import com.baeldung.examples.guice.constant.CommunicationModel; - -public interface CommunicationMode { - - public CommunicationModel getMode(); - - public boolean sendMessage(String message); - -} + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.constant.CommunicationModel; + +public interface CommunicationMode { + + public CommunicationModel getMode(); + + public boolean sendMessage(String message); + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java b/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java index c65644646a..24e0c28dd1 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java +++ b/guice/src/main/java/com/baeldung/examples/guice/DefaultCommunicator.java @@ -1,51 +1,51 @@ - -package com.baeldung.examples.guice; - -import com.baeldung.examples.guice.marker.Communicator; -import com.google.inject.Inject; -import com.google.inject.name.Named; - -/** - * - * @author baeldung - */ -public class DefaultCommunicator implements Communicator { - - private CommunicationMode defaultCommsMode; - @Inject - @Named("SMSComms") - CommunicationMode smsCommsMode; - @Inject - @Named("EmailComms") - CommunicationMode emailCommsMode; - @Inject - @Named("IMComms") - CommunicationMode imCommsMode; - - protected DefaultCommunicator(CommunicationMode defaultComms) { - this.defaultCommsMode = defaultComms; - } - - public DefaultCommunicator() { - - } - - public boolean sendMessage(String message) { - boolean sent = false; - if (defaultCommsMode != null) { - sent = sendMessageByDefault(message); - } else { - sent = smsCommsMode.sendMessage(message); - } - return sent; - } - - private boolean sendMessageByDefault(String message) { - boolean sent = false; - if (message != null && !message.trim().equals("")) { - return defaultCommsMode.sendMessage(message); - } - return sent; - } - -} + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.marker.Communicator; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +/** + * + * @author baeldung + */ +public class DefaultCommunicator implements Communicator { + + private CommunicationMode defaultCommsMode; + @Inject + @Named("SMSComms") + CommunicationMode smsCommsMode; + @Inject + @Named("EmailComms") + CommunicationMode emailCommsMode; + @Inject + @Named("IMComms") + CommunicationMode imCommsMode; + + protected DefaultCommunicator(CommunicationMode defaultComms) { + this.defaultCommsMode = defaultComms; + } + + public DefaultCommunicator() { + + } + + public boolean sendMessage(String message) { + boolean sent = false; + if (defaultCommsMode != null) { + sent = sendMessageByDefault(message); + } else { + sent = smsCommsMode.sendMessage(message); + } + return sent; + } + + private boolean sendMessageByDefault(String message) { + boolean sent = false; + if (message != null && !message.trim().equals("")) { + return defaultCommsMode.sendMessage(message); + } + return sent; + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java index 3caca0edcc..06e77a58e2 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/EmailCommunicationMode.java @@ -1,24 +1,24 @@ - -package com.baeldung.examples.guice; - -import com.baeldung.examples.guice.aop.MessageSentLoggable; -import com.baeldung.examples.guice.constant.CommunicationModel; - -/** - * - * @author baeldung - */ -public class EmailCommunicationMode implements CommunicationMode { - - @Override - public CommunicationModel getMode() { - return CommunicationModel.EMAIL; - } - - @Override - @MessageSentLoggable - public boolean sendMessage(String Message) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - -} + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; + +/** + * + * @author baeldung + */ +public class EmailCommunicationMode implements CommunicationMode { + + @Override + public CommunicationModel getMode() { + return CommunicationModel.EMAIL; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String Message) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java index bc9bd61449..42b0c82b90 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/IMCommunicationMode.java @@ -1,30 +1,30 @@ - -package com.baeldung.examples.guice; - -import com.baeldung.examples.guice.aop.MessageSentLoggable; -import com.baeldung.examples.guice.constant.CommunicationModel; -import com.google.inject.Inject; -import java.util.logging.Logger; - -/** - * - * @author baeldung - */ -public class IMCommunicationMode implements CommunicationMode { - - @Inject - private Logger logger; - - @Override - public CommunicationModel getMode() { - return CommunicationModel.IM; - } - - @Override - @MessageSentLoggable - public boolean sendMessage(String message) { - logger.info("IM Message Sent"); - return true; - } - -} + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; +import com.google.inject.Inject; +import java.util.logging.Logger; + +/** + * + * @author baeldung + */ +public class IMCommunicationMode implements CommunicationMode { + + @Inject + private Logger logger; + + @Override + public CommunicationModel getMode() { + return CommunicationModel.IM; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String message) { + logger.info("IM Message Sent"); + return true; + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java b/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java index 28475839dd..7a30e51f10 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java +++ b/guice/src/main/java/com/baeldung/examples/guice/SMSCommunicationMode.java @@ -1,30 +1,30 @@ - -package com.baeldung.examples.guice; - -import com.baeldung.examples.guice.aop.MessageSentLoggable; -import com.baeldung.examples.guice.constant.CommunicationModel; -import com.google.inject.Inject; -import java.util.logging.Logger; - -/** - * - * @author baeldung - */ -public class SMSCommunicationMode implements CommunicationMode { - - @Inject - private Logger logger; - - @Override - public CommunicationModel getMode() { - return CommunicationModel.SMS; - } - - @Override - @MessageSentLoggable - public boolean sendMessage(String message) { - logger.info("SMS message sent"); - return true; - } - -} + +package com.baeldung.examples.guice; + +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.baeldung.examples.guice.constant.CommunicationModel; +import com.google.inject.Inject; +import java.util.logging.Logger; + +/** + * + * @author baeldung + */ +public class SMSCommunicationMode implements CommunicationMode { + + @Inject + private Logger logger; + + @Override + public CommunicationModel getMode() { + return CommunicationModel.SMS; + } + + @Override + @MessageSentLoggable + public boolean sendMessage(String message) { + logger.info("SMS message sent"); + return true; + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java index 2ad5f8b92e..379cd5f18b 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java +++ b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageLogger.java @@ -1,24 +1,24 @@ - -package com.baeldung.examples.guice.aop; - -import com.google.inject.Inject; -import java.util.logging.Logger; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -/** - * - * @author baeldung - */ -public class MessageLogger implements MethodInterceptor { - - @Override - public Object invoke(MethodInvocation invocation) throws Throwable { - Object[] objectArray = invocation.getArguments(); - int i = 0; - for (Object object : objectArray) { - Logger.getAnonymousLogger().info("Sending message: " + object.toString()); - } - return invocation.proceed(); - } -} + +package com.baeldung.examples.guice.aop; + +import com.google.inject.Inject; +import java.util.logging.Logger; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * + * @author baeldung + */ +public class MessageLogger implements MethodInterceptor { + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + Object[] objectArray = invocation.getArguments(); + int i = 0; + for (Object object : objectArray) { + Logger.getAnonymousLogger().info("Sending message: " + object.toString()); + } + return invocation.proceed(); + } +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java index 5e5a411d0e..431c4bc0ce 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java +++ b/guice/src/main/java/com/baeldung/examples/guice/aop/MessageSentLoggable.java @@ -1,17 +1,17 @@ - -package com.baeldung.examples.guice.aop; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * - * @author baeldung - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface MessageSentLoggable { - -} + +package com.baeldung.examples.guice.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author baeldung + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MessageSentLoggable { + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java b/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java index 109d9a6389..b41dcf16e5 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/binding/AOPModule.java @@ -1,23 +1,23 @@ - -package com.baeldung.examples.guice.binding; - -import com.baeldung.examples.guice.aop.MessageLogger; -import com.baeldung.examples.guice.aop.MessageSentLoggable; -import com.google.inject.AbstractModule; -import com.google.inject.matcher.Matchers; - -/** - * - * @author baeldung - */ -public class AOPModule extends AbstractModule { - - @Override - protected void configure() { - bindInterceptor(Matchers.any(), - Matchers.annotatedWith(MessageSentLoggable.class), - new MessageLogger() - ); - } - -} + +package com.baeldung.examples.guice.binding; + +import com.baeldung.examples.guice.aop.MessageLogger; +import com.baeldung.examples.guice.aop.MessageSentLoggable; +import com.google.inject.AbstractModule; +import com.google.inject.matcher.Matchers; + +/** + * + * @author baeldung + */ +public class AOPModule extends AbstractModule { + + @Override + protected void configure() { + bindInterceptor(Matchers.any(), + Matchers.annotatedWith(MessageSentLoggable.class), + new MessageLogger() + ); + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java b/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java index 93f0fe54ba..1cd9d624ab 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/binding/BasicModule.java @@ -1,37 +1,37 @@ - -package com.baeldung.examples.guice.binding; - -import com.baeldung.examples.guice.Communication; -import com.baeldung.examples.guice.CommunicationMode; -import com.baeldung.examples.guice.DefaultCommunicator; -import com.baeldung.examples.guice.EmailCommunicationMode; -import com.baeldung.examples.guice.IMCommunicationMode; -import com.baeldung.examples.guice.SMSCommunicationMode; -import com.google.inject.AbstractModule; -import com.google.inject.name.Names; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author baeldung - */ -public class BasicModule extends AbstractModule { - - @Override - protected void configure() { - try { - bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.TYPE)); - } catch (NoSuchMethodException ex) { - Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); - } catch (SecurityException ex) { - Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); - } - bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); - - bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); - bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); - bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); - } - -} + +package com.baeldung.examples.guice.binding; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.CommunicationMode; +import com.baeldung.examples.guice.DefaultCommunicator; +import com.baeldung.examples.guice.EmailCommunicationMode; +import com.baeldung.examples.guice.IMCommunicationMode; +import com.baeldung.examples.guice.SMSCommunicationMode; +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author baeldung + */ +public class BasicModule extends AbstractModule { + + @Override + protected void configure() { + try { + bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.TYPE)); + } catch (NoSuchMethodException ex) { + Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } + bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); + + bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); + } + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java b/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java index d12420a0db..3483e9cefd 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java +++ b/guice/src/main/java/com/baeldung/examples/guice/constant/CommunicationModel.java @@ -1,17 +1,17 @@ - -package com.baeldung.examples.guice.constant; - -/** - * - * @author baeldung - */ -public enum CommunicationModel { - - EMAIL("Email"), SMS("SMS"), IM("IM"), PHONE("Phone"); - - final String name; - - CommunicationModel(String name) { - this.name = name; - } -} + +package com.baeldung.examples.guice.constant; + +/** + * + * @author baeldung + */ +public enum CommunicationModel { + + EMAIL("Email"), SMS("SMS"), IM("IM"), PHONE("Phone"); + + final String name; + + CommunicationModel(String name) { + this.name = name; + } +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java b/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java index 7425f1c283..45c729a9a3 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java +++ b/guice/src/main/java/com/baeldung/examples/guice/marker/Communicator.java @@ -1,14 +1,14 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.baeldung.examples.guice.marker; - -/** - * - * @author Tayo - */ -public interface Communicator { - -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.examples.guice.marker; + +/** + * + * @author Tayo + */ +public interface Communicator { + +} diff --git a/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java b/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java index ed83cf3649..f27d8b3a53 100644 --- a/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java +++ b/guice/src/main/java/com/baeldung/examples/guice/modules/BasicModule.java @@ -1,38 +1,38 @@ - -package com.baeldung.examples.guice.modules; - -import com.baeldung.examples.guice.Communication; -import com.baeldung.examples.guice.CommunicationMode; -import com.baeldung.examples.guice.DefaultCommunicator; -import com.baeldung.examples.guice.EmailCommunicationMode; -import com.baeldung.examples.guice.IMCommunicationMode; -import com.baeldung.examples.guice.SMSCommunicationMode; -import com.google.inject.AbstractModule; -import com.google.inject.name.Names; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author baeldung - */ -public class BasicModule extends AbstractModule { - - @Override - protected void configure() { - try { - bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.class)); - bind(Boolean.class).toInstance(true); - } catch (NoSuchMethodException ex) { - Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); - } catch (SecurityException ex) { - Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); - } - bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); - - bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); - bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); - bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); - } - -} + +package com.baeldung.examples.guice.modules; + +import com.baeldung.examples.guice.Communication; +import com.baeldung.examples.guice.CommunicationMode; +import com.baeldung.examples.guice.DefaultCommunicator; +import com.baeldung.examples.guice.EmailCommunicationMode; +import com.baeldung.examples.guice.IMCommunicationMode; +import com.baeldung.examples.guice.SMSCommunicationMode; +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author baeldung + */ +public class BasicModule extends AbstractModule { + + @Override + protected void configure() { + try { + bind(Communication.class).toConstructor(Communication.class.getConstructor(Boolean.class)); + bind(Boolean.class).toInstance(true); + } catch (NoSuchMethodException ex) { + Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(com.baeldung.examples.guice.binding.BasicModule.class.getName()).log(Level.SEVERE, null, ex); + } + bind(DefaultCommunicator.class).annotatedWith(Names.named("AnotherCommunicator")).to(DefaultCommunicator.class).asEagerSingleton(); + + bind(CommunicationMode.class).annotatedWith(Names.named("IMComms")).to(IMCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("EmailComms")).to(EmailCommunicationMode.class); + bind(CommunicationMode.class).annotatedWith(Names.named("SMSComms")).to(SMSCommunicationMode.class); + } + +} diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java b/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java index 9f1345139d..4e4aef2672 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java @@ -1,36 +1,36 @@ -package com.baeldung.javaeeannotations; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebFilter( - urlPatterns = "/bankAccount/*", - filterName = "LogInFilter", - description = "Filter all account transaction URLs" - ) -public class LogInFilter implements javax.servlet.Filter { - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - HttpServletRequest req = (HttpServletRequest) request; - HttpServletResponse res = (HttpServletResponse) response; - - res.sendRedirect(req.getContextPath() + "/login.jsp"); - chain.doFilter(request, response); - } - - @Override - public void destroy() { - } - -} +package com.baeldung.javaeeannotations; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebFilter( + urlPatterns = "/bankAccount/*", + filterName = "LogInFilter", + description = "Filter all account transaction URLs" + ) +public class LogInFilter implements javax.servlet.Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse res = (HttpServletResponse) response; + + res.sendRedirect(req.getContextPath() + "/login.jsp"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + +} diff --git a/libraries/pom.xml b/libraries/pom.xml index eaae539872..85c777b12c 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -1,77 +1,83 @@ - - parent-modules - com.baeldung - 1.0.0-SNAPSHOT - - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 - libraries - libraries - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - + libraries + libraries + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + - - - - cglib - cglib - ${cglib.version} - - - org.apache.commons - commons-lang3 - ${commons-lang.version} - - - junit - junit - ${junit.version} - test - - - org.jasypt - jasypt - ${jasypt.version} - - - org.javatuples - javatuples - ${javatuples.version} - - - org.javassist - javassist - ${javaassist.version} - - - - org.assertj - assertj-core - ${assertj.version} - - + + + + cglib + cglib + ${cglib.version} + + + org.apache.commons + commons-lang3 + ${commons-lang.version} + + + junit + junit + ${junit.version} + test + + + org.jasypt + jasypt + ${jasypt.version} + + + org.javatuples + javatuples + ${javatuples.version} + + + org.javassist + javassist + ${javaassist.version} + + + + org.assertj + assertj-core + ${assertj.version} + + + org.skyscreamer + jsonassert + ${jsonassert.version} + + - - 3.2.4 - 3.5 - 4.12 - 1.9.2 - 1.2 - 3.21.0-GA - 3.6.2 - + + 3.2.4 + 3.5 + 4.12 + 1.9.2 + 1.2 + 3.21.0-GA + 3.6.2 + 1.4.0 + - + \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java b/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java new file mode 100644 index 0000000000..c169d83897 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java @@ -0,0 +1,115 @@ +package com.baeldung.jsonassert; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.skyscreamer.jsonassert.Customization; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.skyscreamer.jsonassert.RegularExpressionValueMatcher; +import org.skyscreamer.jsonassert.comparator.ArraySizeComparator; +import org.skyscreamer.jsonassert.comparator.CustomComparator; + +public class JsonAssertTest { + + @Test + public void givenLenientode_whenAssertEqualsSameJsonString_thenPass() throws JSONException { + String actual = "{id:123,name:\"John\"}"; + JSONAssert.assertEquals("{id:123,name:\"John\"}", actual, JSONCompareMode.LENIENT); + + actual = "{id:123,name:\"John\",zip:\"33025\"}"; + JSONAssert.assertEquals("{id:123,name:\"John\"}", actual, JSONCompareMode.LENIENT); + } + + @Test + public void givenStrictMode_whenAssertNotEqualsExtendedJsonString_thenPass() throws JSONException { + String actual = "{id:123,name:\"John\"}"; + JSONAssert.assertNotEquals("{name:\"John\"}", actual, JSONCompareMode.STRICT); + } + + @Test + public void whenUsingCompareModeOrBoolean_thenBothAreSame() throws JSONException { + String actual = "{id:123,name:\"John\",zip:\"33025\"}"; + JSONAssert.assertEquals("{id:123,name:\"John\"}", actual, JSONCompareMode.LENIENT); + JSONAssert.assertEquals("{id:123,name:\"John\"}", actual, false); + + actual = "{id:123,name:\"John\"}"; + JSONAssert.assertNotEquals("{name:\"John\"}", actual, JSONCompareMode.STRICT); + JSONAssert.assertNotEquals("{name:\"John\"}", actual, true); + } + + @Test + public void givenDifferentOrderForJsonObject_whenAssertEquals_thenPass() throws JSONException { + String result = "{id:1,name:\"John\"}"; + + JSONAssert.assertEquals("{name:\"John\",id:1}", result, JSONCompareMode.STRICT); + JSONAssert.assertEquals("{name:\"John\",id:1}", result, JSONCompareMode.LENIENT); + } + + @Test + public void givenDifferentTypes_whenAssertEqualsSameValue_thenPass() throws JSONException { + JSONObject expected = new JSONObject(); + JSONObject actual = new JSONObject(); + expected.put("id", Integer.valueOf(12345)); + actual.put("id", Double.valueOf(12345)); + + JSONAssert.assertEquals(expected, actual, false); + JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT); + } + + @Test + public void givenNestedObjects_whenAssertEquals_thenPass() throws JSONException { + String result = "{id:1,name:\"Juergen\", address:{city:\"Hollywood\", " + + "state:\"LA\", zip:91601}}"; + JSONAssert.assertEquals("{id:1,name:\"Juergen\", address:{city:\"Hollywood\", " + + "state:\"LA\", zip:91601}}", result, false); + } + + @Test + public void givenArray_whenComparing_thenOrderMustMatchForStrict() throws JSONException { + String result = "[Alex, Barbera, Charlie, Xavier]"; + JSONAssert.assertEquals("[Charlie, Alex, Xavier, Barbera]", result, JSONCompareMode.LENIENT); + JSONAssert.assertEquals("[Alex, Barbera, Charlie, Xavier]", result, JSONCompareMode.STRICT); + JSONAssert.assertNotEquals("[Charlie, Alex, Xavier, Barbera]", result, JSONCompareMode.STRICT); + } + + @Test + public void givenArray_whenComparingExtended_thenNotEqual() throws JSONException { + String result = "[1,2,3,4,5]"; + JSONAssert.assertEquals("[1,2,3,4,5]", result, JSONCompareMode.LENIENT); + JSONAssert.assertNotEquals("[1,2,3]", result, JSONCompareMode.LENIENT); + JSONAssert.assertNotEquals("[1,2,3,4,5,6]", result, JSONCompareMode.LENIENT); + } + + @Test + public void whenComparingSizeOfArray_thenPass() throws JSONException { + String names = "{names:[Alex, Barbera, Charlie, Xavier]}"; + JSONAssert.assertEquals( + "{names:[4]}", + names, + new ArraySizeComparator(JSONCompareMode.LENIENT)); + } + + @Test + public void whenComparingContentsOfArray_thenPass() throws JSONException { + String ratings = "{ratings:[3.2,3.5,4.1,5,1]}"; + JSONAssert.assertEquals( + "{ratings:[1,5]}", + ratings, + new ArraySizeComparator(JSONCompareMode.LENIENT)); + } + + @Test + public void givenValueMatcher_whenComparingUsingRegex_thenPass() throws IllegalArgumentException, JSONException { + JSONAssert.assertEquals("{entry:{id:x}}", "{entry:{id:1, id:2}}", + new CustomComparator( + JSONCompareMode.STRICT, + new Customization("entry.id", + new RegularExpressionValueMatcher("\\d")))); + + JSONAssert.assertNotEquals("{entry:{id:x}}", "{entry:{id:1, id:as}}", + new CustomComparator(JSONCompareMode.STRICT, + new Customization("entry.id", + new RegularExpressionValueMatcher("\\d")))); + } +} diff --git a/xml/src/main/resources/customer-binding.xml b/xml/src/main/resources/customer-binding.xml old mode 100755 new mode 100644 From 202a19acbffe15e8096f7da347d714c6eecfbdf6 Mon Sep 17 00:00:00 2001 From: Mihai Emil Andronache Date: Sun, 19 Mar 2017 11:29:39 +0200 Subject: [PATCH 132/291] Automata indentation and link (#1425) * finite automata example * indentation and link --- algorithms/README.md | 1 + .../baeldung/automata/FiniteStateMachine.java | 12 +- .../automata/RtFiniteStateMachine.java | 34 ++--- .../java/com/baeldung/automata/RtState.java | 10 +- .../com/baeldung/automata/RtTransition.java | 40 +++--- .../java/com/baeldung/automata/State.java | 12 +- .../com/baeldung/automata/Transition.java | 20 +-- .../algorithms/RtFiniteStateMachineTest.java | 122 +++++++++--------- 8 files changed, 126 insertions(+), 125 deletions(-) diff --git a/algorithms/README.md b/algorithms/README.md index 77ef0209c0..a0e10246e0 100644 --- a/algorithms/README.md +++ b/algorithms/README.md @@ -3,3 +3,4 @@ - [Dijkstra Algorithm in Java](http://www.baeldung.com/java-dijkstra) - [Introduction to Cobertura](http://www.baeldung.com/cobertura) - [Ant Colony Optimization](http://www.baeldung.com/java-ant-colony-optimization) +- [Validating Input With Finite Automata in Java](http://www.baeldung.com/finite-automata-java) diff --git a/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java b/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java index cd287ce3d5..943b44fe05 100644 --- a/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java +++ b/algorithms/src/main/java/com/baeldung/automata/FiniteStateMachine.java @@ -5,12 +5,12 @@ package com.baeldung.automata; */ public interface FiniteStateMachine { - /** - * Follow a transition, switch the state of the machine. - * @param c Char. - * @return A new finite state machine with the new state. - */ - FiniteStateMachine switchState(final CharSequence c); + /** + * Follow a transition, switch the state of the machine. + * @param c Char. + * @return A new finite state machine with the new state. + */ + FiniteStateMachine switchState(final CharSequence c); /** * Is the current state a final one? diff --git a/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java b/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java index 7d2293bb33..090e00c73c 100644 --- a/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java +++ b/algorithms/src/main/java/com/baeldung/automata/RtFiniteStateMachine.java @@ -6,25 +6,25 @@ package com.baeldung.automata; */ public final class RtFiniteStateMachine implements FiniteStateMachine { - /** - * Current state. - */ - private State current; + /** + * Current state. + */ + private State current; - /** - * Ctor. - * @param initial Initial state of this machine. - */ - public RtFiniteStateMachine(final State initial) { - this.current = initial; - } + /** + * Ctor. + * @param initial Initial state of this machine. + */ + public RtFiniteStateMachine(final State initial) { + this.current = initial; + } - public FiniteStateMachine switchState(final CharSequence c) { - return new RtFiniteStateMachine(this.current.transit(c)); - } + public FiniteStateMachine switchState(final CharSequence c) { + return new RtFiniteStateMachine(this.current.transit(c)); + } - public boolean canStop() { - return this.current.isFinal(); - } + public boolean canStop() { + return this.current.isFinal(); + } } diff --git a/algorithms/src/main/java/com/baeldung/automata/RtState.java b/algorithms/src/main/java/com/baeldung/automata/RtState.java index 7057335f80..ba785eeff0 100644 --- a/algorithms/src/main/java/com/baeldung/automata/RtState.java +++ b/algorithms/src/main/java/com/baeldung/automata/RtState.java @@ -33,10 +33,10 @@ public final class RtState implements State { return this.isFinal; } - @Override - public State with(Transition tr) { - this.transitions.add(tr); - return this; - } + @Override + public State with(Transition tr) { + this.transitions.add(tr); + return this; + } } diff --git a/algorithms/src/main/java/com/baeldung/automata/RtTransition.java b/algorithms/src/main/java/com/baeldung/automata/RtTransition.java index f895f02e1a..560011e42a 100644 --- a/algorithms/src/main/java/com/baeldung/automata/RtTransition.java +++ b/algorithms/src/main/java/com/baeldung/automata/RtTransition.java @@ -6,26 +6,26 @@ package com.baeldung.automata; */ public final class RtTransition implements Transition { - private String rule; - private State next; - - /** - * Ctor. - * @param rule Rule that a character has to meet - * in order to get to the next state. - * @param next Next state. - */ - public RtTransition (String rule, State next) { - this.rule = rule; - this.next = next; - } - - public State state() { - return this.next; - } + private String rule; + private State next; + + /** + * Ctor. + * @param rule Rule that a character has to meet + * in order to get to the next state. + * @param next Next state. + */ + public RtTransition (String rule, State next) { + this.rule = rule; + this.next = next; + } + + public State state() { + return this.next; + } - public boolean isPossible(CharSequence c) { - return this.rule.equalsIgnoreCase(String.valueOf(c)); - } + public boolean isPossible(CharSequence c) { + return this.rule.equalsIgnoreCase(String.valueOf(c)); + } } diff --git a/algorithms/src/main/java/com/baeldung/automata/State.java b/algorithms/src/main/java/com/baeldung/automata/State.java index 25dff900d2..a25af9d03a 100644 --- a/algorithms/src/main/java/com/baeldung/automata/State.java +++ b/algorithms/src/main/java/com/baeldung/automata/State.java @@ -5,12 +5,12 @@ package com.baeldung.automata; */ public interface State { - /** - * Add a Transition to this state. - * @param tr Given transition. - * @return Modified State. - */ - State with(final Transition tr); + /** + * Add a Transition to this state. + * @param tr Given transition. + * @return Modified State. + */ + State with(final Transition tr); /** * Follow one of the transitions, to get diff --git a/algorithms/src/main/java/com/baeldung/automata/Transition.java b/algorithms/src/main/java/com/baeldung/automata/Transition.java index 9b34617aa1..d57620f911 100644 --- a/algorithms/src/main/java/com/baeldung/automata/Transition.java +++ b/algorithms/src/main/java/com/baeldung/automata/Transition.java @@ -5,16 +5,16 @@ package com.baeldung.automata; */ public interface Transition { - /** - * Is the transition possible with the given character? - * @param c char. - * @return true or false. - */ - boolean isPossible(final CharSequence c); + /** + * Is the transition possible with the given character? + * @param c char. + * @return true or false. + */ + boolean isPossible(final CharSequence c); - /** - * The state to which this transition leads. - * @return State. - */ + /** + * The state to which this transition leads. + * @return State. + */ State state(); } diff --git a/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java b/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java index bd867cbef9..089b38ec3f 100644 --- a/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java +++ b/algorithms/src/test/java/algorithms/RtFiniteStateMachineTest.java @@ -9,74 +9,74 @@ import com.baeldung.automata.*; */ public final class RtFiniteStateMachineTest { - @Test + @Test public void acceptsSimplePair() { - String json = "{\"key\":\"value\"}"; - FiniteStateMachine machine = this.buildJsonStateMachine(); - for (int i=0;i Date: Sun, 19 Mar 2017 08:44:00 -0300 Subject: [PATCH 133/291] BAEL-388 (#1360) * initial push * module Java Web Start (jws) add * pom improvements and fixes --- jws/.gitignore | 7 ++ jws/java-core-samples-lib/jardiff.jar | Bin 0 -> 11346 bytes jws/java-core-samples-lib/jnlp-servlet.jar | Bin 0 -> 54952 bytes jws/pom.xml | 86 +++++++++++++++++++++ jws/src/main/java/com/example/Hello.java | 15 ++++ jws/src/main/webapp/WEB-INF/web.xml | 24 ++++++ jws/src/main/webapp/hello.jnlp | 12 +++ jws/src/main/webapp/index.html | 10 +++ pom.xml | 1 + 9 files changed, 155 insertions(+) create mode 100644 jws/.gitignore create mode 100644 jws/java-core-samples-lib/jardiff.jar create mode 100644 jws/java-core-samples-lib/jnlp-servlet.jar create mode 100644 jws/pom.xml create mode 100644 jws/src/main/java/com/example/Hello.java create mode 100644 jws/src/main/webapp/WEB-INF/web.xml create mode 100644 jws/src/main/webapp/hello.jnlp create mode 100644 jws/src/main/webapp/index.html diff --git a/jws/.gitignore b/jws/.gitignore new file mode 100644 index 0000000000..6346853947 --- /dev/null +++ b/jws/.gitignore @@ -0,0 +1,7 @@ +/target/ +.classpath +.project +.settings +/.settings/ +/settings/ +.tern-project diff --git a/jws/java-core-samples-lib/jardiff.jar b/jws/java-core-samples-lib/jardiff.jar new file mode 100644 index 0000000000000000000000000000000000000000..08b5bb61ab00b5cfe9cd9154f21f42b3a74c10e1 GIT binary patch literal 11346 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 O5A%}>{7c&x>VE(j5h9HM literal 0 HcmV?d00001 diff --git a/jws/java-core-samples-lib/jnlp-servlet.jar b/jws/java-core-samples-lib/jnlp-servlet.jar new file mode 100644 index 0000000000000000000000000000000000000000..c27167c64700a1f2710a1048858695b6454a1037 GIT binary patch literal 54952 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 knbVgl=bxPR{!gr5aS8@7hXMkk2mDPU00H&%|Mu + + 4.0.0 + com.example + jws + war + 0.0.1-SNAPSHOT + + jws-example + + + 3.0.2 + 3.0.0 + 7.0 + 7.0 + + + + + javax.jnlp + jnlp-servlet + ${jnlp-servlet.version} + system + ${project.basedir}/java-core-samples-lib/jnlp-servlet.jar + + + javax.jnlp + jardiff + ${jardiff.version} + system + ${project.basedir}/java-core-samples-lib/jardiff.jar + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + compile + + jar + + + + + com.example.Hello + + + ${project.basedir}/target/jws + + + + + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + + package + + + + + + ${project.basedir}/java-core-samples-lib/ + + **/*.jar + + WEB-INF/lib + + + + + + ${project.artifactId} + + + diff --git a/jws/src/main/java/com/example/Hello.java b/jws/src/main/java/com/example/Hello.java new file mode 100644 index 0000000000..3479277ace --- /dev/null +++ b/jws/src/main/java/com/example/Hello.java @@ -0,0 +1,15 @@ +package com.example; + +import javax.swing.*; + +public class Hello { + public static void main(String[] args) { + JFrame f = new JFrame("main"); + f.setSize(200, 100); + f.setLocationRelativeTo(null); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JLabel label = new JLabel("Hello, world!"); + f.add(label); + f.setVisible(true); + } +} diff --git a/jws/src/main/webapp/WEB-INF/web.xml b/jws/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..18f29ddd12 --- /dev/null +++ b/jws/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + Java Web Start + JNLP Example for Java Web Start Article + + + JnlpDownloadServlet + jnlp.sample.servlet.JnlpDownloadServlet + + + JnlpDownloadServlet + *.jar + + + JnlpDownloadServlet + *.jnlp + + + + index.html + + diff --git a/jws/src/main/webapp/hello.jnlp b/jws/src/main/webapp/hello.jnlp new file mode 100644 index 0000000000..950c0d716f --- /dev/null +++ b/jws/src/main/webapp/hello.jnlp @@ -0,0 +1,12 @@ + + + + Hello + Example + + + + + + + diff --git a/jws/src/main/webapp/index.html b/jws/src/main/webapp/index.html new file mode 100644 index 0000000000..212607b850 --- /dev/null +++ b/jws/src/main/webapp/index.html @@ -0,0 +1,10 @@ + + +Hello World JNLP + + +

+ Launch the example +

+ + diff --git a/pom.xml b/pom.xml index c12562551f..4e55d4686d 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ json jsoup junit5 + jws kotlin From 04d8fed1c5bfe9f1f42893cf8dddfc3e601fbd3d Mon Sep 17 00:00:00 2001 From: lor6 Date: Sun, 19 Mar 2017 17:25:11 +0200 Subject: [PATCH 134/291] validation with mvc and angular (#1378) * validation with mvc and angular * fix dependency versions --- spring-mvc-forms/pom.xml | 11 ++- .../ApplicationConfiguration.java | 10 +++ .../controller/UserController.java | 63 +++++++++++++++ .../baeldung/springmvcforms/domain/User.java | 71 +++++++++++++++++ .../src/main/webapp/WEB-INF/html/user.html | 68 ++++++++++++++++ spring-mvc-forms/src/main/webapp/css/user.css | 77 +++++++++++++++++++ spring-mvc-forms/src/main/webapp/js/app.js | 70 +++++++++++++++++ 7 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java create mode 100644 spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/domain/User.java create mode 100644 spring-mvc-forms/src/main/webapp/WEB-INF/html/user.html create mode 100644 spring-mvc-forms/src/main/webapp/css/user.css create mode 100644 spring-mvc-forms/src/main/webapp/js/app.js diff --git a/spring-mvc-forms/pom.xml b/spring-mvc-forms/pom.xml index 35ed00c0e9..e5ffb52801 100644 --- a/spring-mvc-forms/pom.xml +++ b/spring-mvc-forms/pom.xml @@ -46,6 +46,12 @@ commons-fileupload ${fileupload.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + @@ -89,16 +95,17 @@ - 4.3.4.RELEASE + 4.3.7.RELEASE 2.6 1.2 2.3.1 3.1.0 3.6.0 1.8 - 5.3.3.Final + 5.4.0.Final enter-location-of-server 1.3.2 + 2.8.7 diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/ApplicationConfiguration.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/ApplicationConfiguration.java index 3f7889422f..7292d95b21 100644 --- a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/ApplicationConfiguration.java +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/ApplicationConfiguration.java @@ -27,6 +27,16 @@ class ApplicationConfiguration extends WebMvcConfigurerAdapter { bean.setSuffix(".jsp"); return bean; } + + + @Bean + public InternalResourceViewResolver htmlViewResolver() { + InternalResourceViewResolver bean = new InternalResourceViewResolver(); + bean.setPrefix("/WEB-INF/html/"); + bean.setSuffix(".html"); + bean.setOrder(2); + return bean; + } @Bean public MultipartResolver multipartResolver() { diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java new file mode 100644 index 0000000000..880b224dd9 --- /dev/null +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java @@ -0,0 +1,63 @@ +package com.baeldung.springmvcforms.controller; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.baeldung.springmvcforms.domain.User; + +@Controller +public class UserController { + + List users = new ArrayList() { + { + add(new User("ana@yahoo.com", "pass", "Ana", 20)); + add(new User("bob@yahoo.com", "pass", "Bob", 30)); + add(new User("john@yahoo.com", "pass", "John", 40)); + add(new User("mary@yahoo.com", "pass", "Mary", 30)); + } + }; + + @GetMapping("/userPage") + public String getUserProfilePage() { + return "user"; + } + + @PostMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResponseEntity saveUser(@Valid User user, BindingResult result, Model model) { + if (result.hasErrors()) { + List errors = new ArrayList<>(); + result.getAllErrors().forEach(item->{ + errors.add(item.getDefaultMessage()); + }); + return new ResponseEntity<>(errors, HttpStatus.OK); + } else { + if (users.stream().anyMatch(it -> user.getEmail().equals(it.getEmail()))) { + return new ResponseEntity<>(Collections.singletonList("Email already exists!"), HttpStatus.CONFLICT); + } else { + users.add(user); + return new ResponseEntity<>(HttpStatus.CREATED); + } + } + } + + @GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public List getUsers() { + return users; + } + +} diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/domain/User.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/domain/User.java new file mode 100644 index 0000000000..49f006f422 --- /dev/null +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/domain/User.java @@ -0,0 +1,71 @@ +package com.baeldung.springmvcforms.domain; + +import javax.validation.constraints.Digits; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.hibernate.validator.constraints.Email; +import org.hibernate.validator.constraints.NotBlank; + +public class User { + + @NotNull + @Email + private String email; + + @NotNull + @Size(min = 4, max = 15) + private String password; + + @NotBlank + private String name; + + @Min(18) + @Digits(integer = 2, fraction = 0) + private int age; + + public User() { + + } + + public User(String email, String password, String name, int age) { + super(); + this.email = email; + this.password = password; + this.name = name; + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/html/user.html b/spring-mvc-forms/src/main/webapp/WEB-INF/html/user.html new file mode 100644 index 0000000000..a505f51f32 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/html/user.html @@ -0,0 +1,68 @@ + + + + +Users + + + + + + + + +
+ + + +
+

Invalid email!

+

Email is required!

+
+
+ + + +
+

Password must be at least 4 characters!

+

Password must not be longer than 15 characters!

+

Password is required!

+
+
+ + + +
+

Name is required!

+
+
+ + + +
+

Age must be greater than 18!

+

Age must be greater than 18!

+
+
+
+ + +
+ +
+
{{errorMessage}}
+
{{message}}
+
+ +All Users:
+ + + + + + + +
EmailNameAge
{{usr.email}} {{usr.name}} {{usr.age}}
+ + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/css/user.css b/spring-mvc-forms/src/main/webapp/css/user.css new file mode 100644 index 0000000000..bcfb62a33c --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/css/user.css @@ -0,0 +1,77 @@ +.form-label { + display:block; + margin-top:16px; + font-weight:bold; +} + +.form-input { + border-radius:5px; + display:inline; +} + +.form-input p { + margin:0; +} + +.form-button { + margin:5px; +} + +.form-error input.ng-invalid { + border-color:red; +} + +.check { + display:inline; + color:green; + font-weight:bold; +} + +.error-messages { + color:red; +} + +.error-messages p { + margin:0; +} + +#customers { + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; + border-collapse: collapse; + width: 100%; +} + +#users td, #users th { + border: 1px solid dodgerblue; + border-collapse:collapse; + padding: 4px; + width:200px; +} + +#users tr:nth-child(even){background-color: lavender;} + +#users th { + padding-top: 10px; + padding-bottom: 10px; + text-align: left; + background-color: dodgerblue; +} + +#users { + border-collapse:collapse; +} + +button { + border-radius:5px; + cursor:pointer; + margin:10px; + padding:5px; +} + +.form-button-save { + background-color:lightgreen; +} + +.form-button-reset { + background-color:lightpink; +} \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/js/app.js b/spring-mvc-forms/src/main/webapp/js/app.js new file mode 100644 index 0000000000..6a290b3cf0 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/js/app.js @@ -0,0 +1,70 @@ +var app = angular.module('app', ['ngMessages']); + +app.controller('UserCtrl', ['$scope','UserService', function ($scope,UserService) { + + $scope.submitted = false; + + $scope.getUsers = function() { + UserService.getUsers().then( function(data){ + $scope.users = data; + }); + } + + $scope.saveUser = function () { + $scope.submitted = true; + if ($scope.userForm.$valid){ + UserService.saveUser($scope.user) + .then (function success(response){ + $scope.message = 'User added!'; + $scope.errorMessage = ''; + $scope.getUsers(); + $scope.user = null; + $scope.submitted = false; + }, + function error(response){ + if (response.status == 409){ + $scope.errorMessage = response.data[0]; + } + else { + $scope.errorMessage = 'Error adding user!'; + } + $scope.message = ''; + }); + } + } + + $scope.getUsers(); + + $scope.resetForm = function () { + $scope.userForm.$setPristine(); + $scope.user=null; + $scope.message=''; + $scope.errorMessage=''; + $scope.submitted = false; + } + +}]); + +app.service('UserService',['$http', function ($http) { + + this.saveUser = function saveUser(user){ + return $http({ + method: 'POST', + url: 'user', + params: {email:user.email, password:user.password, name:user.name, age:user.age}, + headers: 'Accept:application/json' + }); + } + + + this.getUsers = function getUsers(){ + return $http({ + method: 'GET', + url: 'users', + headers:'Accept:application/json' + }).then( function(response){ + return response.data; + } ); + } + +}]); \ No newline at end of file From 32147b4459f9b21db59660e04a0885ff86c5f051 Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Sun, 19 Mar 2017 22:28:34 +0530 Subject: [PATCH 135/291] BAEL-702 Intro to Vert.x Initial commit --- pom.xml | 7 +- vertx/pom.xml | 111 ++++++++++++++++++ vertx/src/main/conf/conf.json | 3 + .../main/java/com/baeldung/HelloVerticle.java | 28 +++++ .../com/baeldung/SimpleServerVerticle.java | 26 ++++ .../main/java/com/baeldung/model/Article.java | 59 ++++++++++ .../baledung/rest/RestServiceVerticle.java | 41 +++++++ vertx/src/resources/logback.xml | 14 +++ .../com/baeldung/RestServiceVerticleTest.java | 46 ++++++++ .../baeldung/SimpleServerVerticleTest.java | 47 ++++++++ 10 files changed, 378 insertions(+), 4 deletions(-) create mode 100644 vertx/pom.xml create mode 100644 vertx/src/main/conf/conf.json create mode 100644 vertx/src/main/java/com/baeldung/HelloVerticle.java create mode 100644 vertx/src/main/java/com/baeldung/SimpleServerVerticle.java create mode 100644 vertx/src/main/java/com/baeldung/model/Article.java create mode 100644 vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java create mode 100644 vertx/src/resources/logback.xml create mode 100644 vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java create mode 100644 vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java diff --git a/pom.xml b/pom.xml index 9c24200a0b..312e2aef9f 100644 --- a/pom.xml +++ b/pom.xml @@ -203,9 +203,8 @@ apache-solrj rabbitmq - - - + vertx + @@ -216,4 +215,4 @@ --> - + \ No newline at end of file diff --git a/vertx/pom.xml b/vertx/pom.xml new file mode 100644 index 0000000000..971a61d336 --- /dev/null +++ b/vertx/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + com.baeldung + vertx + 1.0-SNAPSHOT + vertx + http://maven.apache.org + + + junit + junit + 4.12 + test + + + + io.vertx + vertx-core + 3.0.0 + + + + io.vertx + vertx-web + 3.0.0 + + + + io.vertx + vertx-unit + 3.0.0 + test + + + + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + + + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + + + + io.vertx.core.Starter + com.baeldung.SimpleServerVerticle + + + + + ${project.build.directory}/${project.artifactId}-${project.version}-app.jar + + + + + + + + + + + 1.7.21 + 1.1.7 + + + 6.10 + + + 3.6.0 + 2.19.1 + + + + diff --git a/vertx/src/main/conf/conf.json b/vertx/src/main/conf/conf.json new file mode 100644 index 0000000000..4fa43ee648 --- /dev/null +++ b/vertx/src/main/conf/conf.json @@ -0,0 +1,3 @@ +{ + "http.port":8080 +} \ No newline at end of file diff --git a/vertx/src/main/java/com/baeldung/HelloVerticle.java b/vertx/src/main/java/com/baeldung/HelloVerticle.java new file mode 100644 index 0000000000..98d1b336a3 --- /dev/null +++ b/vertx/src/main/java/com/baeldung/HelloVerticle.java @@ -0,0 +1,28 @@ +package com.baeldung; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; +import io.vertx.core.Vertx; + +public class HelloVerticle extends AbstractVerticle { + private static final Logger LOGGER = LoggerFactory.getLogger(HelloVerticle.class); + + @Override + public void start(Future future) { + LOGGER.info("Welcome to Vertx"); + } + + @Override + public void stop() { + LOGGER.info("Shutting down application"); + } + + public static void main(String[] args) { + Vertx vertx = Vertx.vertx(); + vertx.deployVerticle(new HelloVerticle()); + } +} + diff --git a/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java new file mode 100644 index 0000000000..2cee37903b --- /dev/null +++ b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java @@ -0,0 +1,26 @@ +package com.baeldung; + +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; + +public class SimpleServerVerticle extends AbstractVerticle { + + @Override + public void start(Future future) { + vertx.createHttpServer() + .requestHandler(request -> { + request.response() + .end("Welcome to Vert.x Intro"); + }) + .listen(config().getInteger("http.port", 8080), result -> { + if (result.succeeded()) { + future.complete(); + } else { + future.fail(result.cause()); + } + }); + } + +} + + diff --git a/vertx/src/main/java/com/baeldung/model/Article.java b/vertx/src/main/java/com/baeldung/model/Article.java new file mode 100644 index 0000000000..9f1fdb8203 --- /dev/null +++ b/vertx/src/main/java/com/baeldung/model/Article.java @@ -0,0 +1,59 @@ +package com.baeldung.model; + +public class Article { + private String id; + private String content; + private String author; + private String datePublished; + private int wordCount; + + public Article(String id, String content, String author, String datePublished, int wordCount) { + super(); + this.id = id; + this.content = content; + this.author = author; + this.datePublished = datePublished; + this.wordCount = wordCount; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getDatePublished() { + return datePublished; + } + + public void setDatePublished(String datePublished) { + this.datePublished = datePublished; + } + + public int getWordCount() { + return wordCount; + } + + public void setWordCount(int wordCount) { + this.wordCount = wordCount; + } + +} diff --git a/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java b/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java new file mode 100644 index 0000000000..181b3007d5 --- /dev/null +++ b/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java @@ -0,0 +1,41 @@ +package com.baledung.rest; + +import com.baeldung.model.Article; + +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; +import io.vertx.core.json.Json; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; + +public class RestServiceVerticle extends AbstractVerticle { + @Override + public void start(Future future) { + + Router router = Router.router(vertx); + router.get("/api/baeldung/articles/article/:id") + .handler(this::getArticles); + + vertx.createHttpServer() + .requestHandler(router::accept) + .listen(config().getInteger("http.port", 8080), result -> { + if (result.succeeded()) { + future.complete(); + } else { + future.fail(result.cause()); + } + }); + } + + private void getArticles(RoutingContext routingContext) { + String articleId = routingContext.request() + .getParam("id"); + Article article = new Article(articleId, "This is an intro to vertx", "baeldung", "01-02-2017", 1578); + + routingContext.response() + .putHeader("content-type", "application/json") + .setStatusCode(200) + .end(Json.encodePrettily(article)); + } + +} diff --git a/vertx/src/resources/logback.xml b/vertx/src/resources/logback.xml new file mode 100644 index 0000000000..e9ae1894a6 --- /dev/null +++ b/vertx/src/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + \ No newline at end of file diff --git a/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java b/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java new file mode 100644 index 0000000000..8eebe1396d --- /dev/null +++ b/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java @@ -0,0 +1,46 @@ +package com.baeldung; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.baledung.rest.RestServiceVerticle; + +import io.vertx.core.Vertx; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; + +@RunWith(VertxUnitRunner.class) +public class RestServiceVerticleTest { + + private Vertx vertx; + + @Before + public void setup(TestContext testContext) { + vertx = Vertx.vertx(); + + vertx.deployVerticle(RestServiceVerticle.class.getName(), testContext.asyncAssertSuccess()); + } + + @After + public void tearDown(TestContext testContext) { + vertx.close(testContext.asyncAssertSuccess()); + } + + @Test + public void givenId_whenReceivedArticle_thenSuccess(TestContext testContext) { + final Async async = testContext.async(); + + vertx.createHttpClient() + .getNow(8080, "localhost", "/api/baeldung/articles/article/12345", response -> { + response.handler(responseBody -> { + testContext.assertTrue(responseBody.toString() + .contains("\"id\" : \"12345\"")); + async.complete(); + }); + }); + } + +} diff --git a/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java b/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java new file mode 100644 index 0000000000..177f8d8435 --- /dev/null +++ b/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java @@ -0,0 +1,47 @@ +package com.baeldung; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import io.vertx.core.DeploymentOptions; +import io.vertx.core.Vertx; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; + +@RunWith(VertxUnitRunner.class) +public class SimpleServerVerticleTest { + private Vertx vertx; + + @Before + public void setup(TestContext testContext) { + vertx = Vertx.vertx(); + + vertx.deployVerticle(SimpleServerVerticle.class.getName(), + testContext.asyncAssertSuccess()); + } + + @After + public void tearDown(TestContext testContext) { + vertx.close(testContext.asyncAssertSuccess()); + } + + @Test + public void whenReceivedResponse_thenSuccess(TestContext testContext) { + final Async async = testContext.async(); + + vertx.createHttpClient() + .getNow(8080, "localhost", "/", response -> { + response.handler(responseBody -> { + testContext.assertTrue(responseBody.toString() + .contains("Welcome")); + async.complete(); + }); + }); + } + +} + From 32c21f27221951c78f89782c6579b0814ee3599a Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Sun, 19 Mar 2017 13:55:38 -0500 Subject: [PATCH 136/291] BAEL-731: Updated README (#1452) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md --- spring-boot/README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index d70e83525b..8aa5957bad 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -14,4 +14,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) - [Guide to Spring WebUtils and ServletRequestUtils](http://www.baeldung.com/spring-webutils-servletrequestutils) - [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) +- [Guide to Internationalization in Spring Boot](http://www.baeldung.com/spring-boot-internationalization) From debde5ad67c020cdcf000a5ebb8b1ca126749e6c Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 20:02:04 +0100 Subject: [PATCH 137/291] Update README.md (#1439) --- spring-security-mvc-login/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-security-mvc-login/README.md b/spring-security-mvc-login/README.md index 35305112b4..f7eb314869 100644 --- a/spring-security-mvc-login/README.md +++ b/spring-security-mvc-login/README.md @@ -11,6 +11,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Spring Security Expressions – hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) - [Spring HTTP/HTTPS Channel Security](http://www.baeldung.com/spring-channel-security-https) - [Spring Security - Customize the 403 Forbidden/Access Denied Page](http://www.baeldung.com/spring-security-custom-access-denied-page) +- [Spring Security – Redirect to the Previous URL After Login](http://www.baeldung.com/spring-security-redirect-login) ### Build the Project ``` From 7d670d2be6b1369561b02358cac3f64b5a181595 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 20:02:15 +0100 Subject: [PATCH 138/291] Update README.md (#1442) --- spring-ldap/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spring-ldap/README.md b/spring-ldap/README.md index 8dffadb685..f77572d982 100644 --- a/spring-ldap/README.md +++ b/spring-ldap/README.md @@ -1,8 +1,9 @@ +## Spring LDAP Example Project + ### Relevant articles - [Spring LDAP Overview](http://www.baeldung.com/spring-ldap) +- [Spring LDAP Example Project](http://www.baeldung.com/spring-ldap-overview/) -## Spring LDAP Example Project -- (http://www.baeldung.com/spring-ldap-overview/) From e693c47019d6d39c15e4596a8816984abcfe08d4 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 20:02:29 +0100 Subject: [PATCH 139/291] Delete README.md (#1440) --- spring-5/src/test/java/com/baeldung/README.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 spring-5/src/test/java/com/baeldung/README.md diff --git a/spring-5/src/test/java/com/baeldung/README.md b/spring-5/src/test/java/com/baeldung/README.md deleted file mode 100644 index f7b358ec3e..0000000000 --- a/spring-5/src/test/java/com/baeldung/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Relevant articles - -- [Concurrent Test Execution in Spring 5](http://www.baeldung.com/spring-5-concurrent-tests) From 365d9b70230c644c5012ed367a39ad06ad3262b0 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 20:02:50 +0100 Subject: [PATCH 140/291] Update README.md (#1441) --- spring-5/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spring-5/README.md b/spring-5/README.md index 0914388b49..47a5314009 100644 --- a/spring-5/README.md +++ b/spring-5/README.md @@ -1,6 +1,8 @@ ## Spring REST Example Project -###The Course +### The Course The "REST With Spring" Classes: http://bit.ly/restwithspring -### Relevant Articles: +### Relevant Articles + +- [Concurrent Test Execution in Spring 5](http://www.baeldung.com/spring-5-concurrent-tests) From e71367b3f3f972558097d56020ec46af26ea78e4 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 20:03:23 +0100 Subject: [PATCH 141/291] Assembly plugin fix (#1449) * Assembly plugin fix * Fix java opts * Fix java opts 2 * Fix java opts 3 * Add sudo: required * Remove sudo: required * Enable incremental builder * Disable incremental builder * Update * Update --- .travis.yml | 13 +++++-------- apache-poi/temp.xlsx | Bin 3510 -> 3492 bytes core-java/pom.xml | 1 + disruptor/pom.xml | 1 + jpa-storedprocedure/pom.xml | 1 + pom.xml | 14 +++++++++++++- xml/pom.xml | 1 + 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6063fbf3e5..120d365569 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: java -install: travis_wait 40 mvn -q clean install -Dgib.enabled=true +install: travis_wait 60 mvn -q clean install + +before_script: + - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseGCOverheadLimit'" > ~/.mavenrc jdk: - oraclejdk8 @@ -14,10 +17,4 @@ cache: directories: - .autoconf - $HOME/.m2 - - sudo: required - - env: - global: - JAVA_OPTS="-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" - MAVEN_OPTS="-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" + diff --git a/apache-poi/temp.xlsx b/apache-poi/temp.xlsx index 50307a28c2ae5c64afdcaf6baae59a0648c28c6b..cbea3a410d193a848a5321af8e311bcf61f7160f 100644 GIT binary patch literal 3492 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 + ${project.basedir} org.baeldung.executable.ExecutableMavenJar diff --git a/disruptor/pom.xml b/disruptor/pom.xml index 7f2c78c9b0..2523cc2125 100644 --- a/disruptor/pom.xml +++ b/disruptor/pom.xml @@ -145,6 +145,7 @@ single + ${project.basedir} org.baeldung.executable.ExecutableMavenJar diff --git a/jpa-storedprocedure/pom.xml b/jpa-storedprocedure/pom.xml index 797303dc29..1672afd217 100644 --- a/jpa-storedprocedure/pom.xml +++ b/jpa-storedprocedure/pom.xml @@ -30,6 +30,7 @@ maven-assembly-plugin + ${project.basedir} jar-with-dependencies diff --git a/pom.xml b/pom.xml index 4e55d4686d..d68a7d0749 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ UTF-8 refs/heads/master - false + @@ -211,6 +211,18 @@ + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + maven + + + + + maven-assembly-plugin + ${project.basedir} jar-with-dependencies From 6bd430c4644e93e7cc400e22b8cfeae712cead12 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 21:37:44 +0100 Subject: [PATCH 142/291] Update .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 120d365569..b5bd4684a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: java install: travis_wait 60 mvn -q clean install +sudo: required + before_script: - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseGCOverheadLimit'" > ~/.mavenrc From 6c3f4d868837fed7e5f880593fdebd8152821487 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 21:37:59 +0100 Subject: [PATCH 143/291] Update .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5bd4684a3..120d365569 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: java install: travis_wait 60 mvn -q clean install -sudo: required - before_script: - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseGCOverheadLimit'" > ~/.mavenrc From 0b78cc9e4c0b5c32f6d7469f45cd96bd91275fdd Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Sun, 19 Mar 2017 21:29:10 +0000 Subject: [PATCH 144/291] Custom aop (#1451) --- spring-custom-aop/pom.xml | 53 +++++++++++++++++++ .../main/java/org/baeldung/Application.java | 13 +++++ .../main/java/org/baeldung/ExampleAspect.java | 25 +++++++++ .../java/org/baeldung/LogExecutionTime.java | 11 ++++ .../src/main/java/org/baeldung/Service.java | 12 +++++ .../org/baeldung/CustomAnnotationTest.java | 21 ++++++++ 6 files changed, 135 insertions(+) create mode 100644 spring-custom-aop/pom.xml create mode 100644 spring-custom-aop/src/main/java/org/baeldung/Application.java create mode 100644 spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java create mode 100644 spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java create mode 100644 spring-custom-aop/src/main/java/org/baeldung/Service.java create mode 100644 spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java diff --git a/spring-custom-aop/pom.xml b/spring-custom-aop/pom.xml new file mode 100644 index 0000000000..1c3b5bdccd --- /dev/null +++ b/spring-custom-aop/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + com.baeldung + spring-custom-aop + 0.0.1-SNAPSHOT + war + spring-custom-aop + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + diff --git a/spring-custom-aop/src/main/java/org/baeldung/Application.java b/spring-custom-aop/src/main/java/org/baeldung/Application.java new file mode 100644 index 0000000000..e5c764ef7e --- /dev/null +++ b/spring-custom-aop/src/main/java/org/baeldung/Application.java @@ -0,0 +1,13 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java b/spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java new file mode 100644 index 0000000000..7c3b5fb599 --- /dev/null +++ b/spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java @@ -0,0 +1,25 @@ +package org.baeldung; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ExampleAspect { + + @Around("@annotation(LogExecutionTime)") + public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { + final long start = System.currentTimeMillis(); + + final Object proceed = joinPoint.proceed(); + + final long executionTime = System.currentTimeMillis() - start; + + System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms"); + + return proceed; + } + +} diff --git a/spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java b/spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java new file mode 100644 index 0000000000..c10f97e78f --- /dev/null +++ b/spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java @@ -0,0 +1,11 @@ +package org.baeldung; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface LogExecutionTime { +} diff --git a/spring-custom-aop/src/main/java/org/baeldung/Service.java b/spring-custom-aop/src/main/java/org/baeldung/Service.java new file mode 100644 index 0000000000..e4bee38438 --- /dev/null +++ b/spring-custom-aop/src/main/java/org/baeldung/Service.java @@ -0,0 +1,12 @@ +package org.baeldung; + +import org.springframework.stereotype.Component; + +@Component +public class Service { + + @LogExecutionTime + public void serve() throws InterruptedException { + Thread.sleep(2000); + } +} diff --git a/spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java b/spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java new file mode 100644 index 0000000000..d4712cc063 --- /dev/null +++ b/spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java @@ -0,0 +1,21 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class CustomAnnotationTest { + + @Autowired + private Service service; + + @Test + public void shouldApplyCustomAnnotation() throws InterruptedException { + service.serve(); + } + +} From 3accbf88156f1aa4850dd29c7dae8a9b42e0f255 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sun, 19 Mar 2017 22:31:11 +0100 Subject: [PATCH 145/291] UserController refactor (#1450) * Refactor UserController * Refactor UserController --- .../controller/UserController.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java index 880b224dd9..f5553cf2b7 100644 --- a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UserController.java @@ -1,48 +1,44 @@ package com.baeldung.springmvcforms.controller; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.validation.Valid; +import com.baeldung.springmvcforms.domain.User; +import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; -import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; -import com.baeldung.springmvcforms.domain.User; +import javax.validation.Valid; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; @Controller public class UserController { - List users = new ArrayList() { - { - add(new User("ana@yahoo.com", "pass", "Ana", 20)); - add(new User("bob@yahoo.com", "pass", "Bob", 30)); - add(new User("john@yahoo.com", "pass", "John", 40)); - add(new User("mary@yahoo.com", "pass", "Mary", 30)); - } - }; + private List users = Arrays.asList( + new User("ana@yahoo.com", "pass", "Ana", 20), + new User("bob@yahoo.com", "pass", "Bob", 30), + new User("john@yahoo.com", "pass", "John", 40), + new User("mary@yahoo.com", "pass", "Mary", 30)); @GetMapping("/userPage") public String getUserProfilePage() { return "user"; } - @PostMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping("/user") @ResponseBody public ResponseEntity saveUser(@Valid User user, BindingResult result, Model model) { if (result.hasErrors()) { - List errors = new ArrayList<>(); - result.getAllErrors().forEach(item->{ - errors.add(item.getDefaultMessage()); - }); + final List errors = result.getAllErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.toList()); + return new ResponseEntity<>(errors, HttpStatus.OK); } else { if (users.stream().anyMatch(it -> user.getEmail().equals(it.getEmail()))) { @@ -54,7 +50,7 @@ public class UserController { } } - @GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping("/users") @ResponseBody public List getUsers() { return users; From ed70f6b3380c3a6e597209e3787e14a0c098f8f0 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 20 Mar 2017 09:15:49 +0100 Subject: [PATCH 146/291] Finite Automata refactor (#1445) --- .../src/main/java/com/baeldung/automata/RtState.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/algorithms/src/main/java/com/baeldung/automata/RtState.java b/algorithms/src/main/java/com/baeldung/automata/RtState.java index ba785eeff0..b4a5df7961 100644 --- a/algorithms/src/main/java/com/baeldung/automata/RtState.java +++ b/algorithms/src/main/java/com/baeldung/automata/RtState.java @@ -21,12 +21,12 @@ public final class RtState implements State { } public State transit(final CharSequence c) { - for(final Transition t : this.transitions) { - if(t.isPossible(c)) { - return t.state(); - } - } - throw new IllegalArgumentException("Input not accepted: " + c); + return transitions + .stream() + .filter(t -> t.isPossible(c)) + .map(Transition::state) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Input not accepted: " + c)); } public boolean isFinal() { From 64c2ef150e7cbbc1e9b9001734698790576e1706 Mon Sep 17 00:00:00 2001 From: Devendra Tiwari Date: Mon, 20 Mar 2017 13:46:34 +0530 Subject: [PATCH 147/291] Guava 21 (#1411) Code for article Guava 21 | common.collect package --- guava21/README.md | 7 + guava21/pom.xml | 41 +++++ .../guava/tutorial/ComparatorsExamples.java | 27 +++ .../guava/tutorial/ConcatStreams.java | 11 ++ .../tutorial/InternerBuilderExample.java | 19 +++ .../guava/tutorial/MoreCollectorsExample.java | 17 ++ .../guava/tutorial/StreamsUtility.java | 42 +++++ .../src/test/java/ComparatorsUnitTests.java | 76 +++++++++ guava21/src/test/java/GauavaStreamsTests.java | 155 ++++++++++++++++++ .../src/test/java/InternBuilderUnitTests.java | 19 +++ .../test/java/MoreCollectorsUnitTests.java | 36 ++++ guava21/src/test/java/StreamUtility.java | 66 ++++++++ 12 files changed, 516 insertions(+) create mode 100644 guava21/README.md create mode 100644 guava21/pom.xml create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java create mode 100644 guava21/src/test/java/ComparatorsUnitTests.java create mode 100644 guava21/src/test/java/GauavaStreamsTests.java create mode 100644 guava21/src/test/java/InternBuilderUnitTests.java create mode 100644 guava21/src/test/java/MoreCollectorsUnitTests.java create mode 100644 guava21/src/test/java/StreamUtility.java diff --git a/guava21/README.md b/guava21/README.md new file mode 100644 index 0000000000..8121cf2ea6 --- /dev/null +++ b/guava21/README.md @@ -0,0 +1,7 @@ +========= + +## Guava 21 + +**Important**: Guava 21.0 requires Java 8. If you need Java 6, 7 or Android compatibility, use Guava 20.0 for now. Guava 22.0 and on will introduce a Java 6/Android compatible backport of Guava that includes all of the latest changes that don't require Java 8. + +Article 1 : Introduction to Guava21 common.collect package. \ No newline at end of file diff --git a/guava21/pom.xml b/guava21/pom.xml new file mode 100644 index 0000000000..f393c65aec --- /dev/null +++ b/guava21/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + com.baeldung.guava + tutorial + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + + + com.google.guava + guava + 21.0 + + + + + junit + junit + 4.11 + + + + + + \ No newline at end of file diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java b/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java new file mode 100644 index 0000000000..6eb5c7f5ba --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java @@ -0,0 +1,27 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.collect.Comparators; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class ComparatorsExamples { + + public static void main(String[] args){ + + List integers = Arrays.asList(1,2,3,4,4,6,7,8,9,10); + //This will return true + boolean isInAscendingOrder = Comparators.isInOrder(integers, new AscedingOrderComparator()); + + System.out.println(isInAscendingOrder); + + } + + private static class AscedingOrderComparator implements Comparator { + @Override + public int compare(Integer o1, Integer o2) { + return o1.compareTo(o2); + } + } +} diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java b/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java new file mode 100644 index 0000000000..ab95b85751 --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java @@ -0,0 +1,11 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.collect.Streams; + +import java.util.stream.Stream; + +public class ConcatStreams { + public static Stream concatStreams(Stream stream1, Stream stream2, Stream stream3){ + return Streams.concat(stream1,stream2,stream3); + } +} diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java new file mode 100644 index 0000000000..6b935ba2a8 --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java @@ -0,0 +1,19 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; + +import static com.google.common.collect.Interners.newBuilder; + +public class InternerBuilderExample { + + public static void main(String[] args){ + Interner interners = Interners.newBuilder() + .concurrencyLevel(2) + .strong() + .build(); + + + } + +} diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java new file mode 100644 index 0000000000..6cf4b6b0ac --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java @@ -0,0 +1,17 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.collect.MoreCollectors; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class MoreCollectorsExample { + + public static void main(String[] args) { + List numbers = Arrays.asList(1); + Optional number = numbers.stream() + .map(e -> e * 2) + .collect(MoreCollectors.toOptional()); + } +} diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java b/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java new file mode 100644 index 0000000000..4ec3b44ef4 --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java @@ -0,0 +1,42 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.collect.Streams; + +import java.util.*; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +public class StreamsUtility { + + public static void main(String[] args){ + + List numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20); + //Using Collection + Stream streamFromCollection = Streams.stream(numbers); + //Using Iterator + Stream streamFromIterator = Streams.stream(numbers.iterator()); + //Using Iterable + Stream streamFromIterable = Streams.stream((Iterable) numbers); + //Using Optional + Stream streamFromOptional = Streams.stream(Optional.of(1)); + //Using OptionalLong to LongStream + LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1)); + //Using OptionalInt to IntStream + IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1)); + //Using OptionalDouble to DoubleStream + DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0)); + + Stream concatenatedStreams = Streams.concat(streamFromCollection,streamFromIterable,streamFromIterator); + + List integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10); + //This will return 10 + Optional lastItem = Streams.findLast(integers.stream()); + + Streams.zip( + Stream.of("candy", "chocolate", "bar"), + Stream.of("$1", "$2","$3"), + (arg1, arg2) -> arg1 + ":" + arg2); + } +} diff --git a/guava21/src/test/java/ComparatorsUnitTests.java b/guava21/src/test/java/ComparatorsUnitTests.java new file mode 100644 index 0000000000..f196c41a1b --- /dev/null +++ b/guava21/src/test/java/ComparatorsUnitTests.java @@ -0,0 +1,76 @@ +import com.google.common.collect.Comparators; +import org.junit.Assert; +import org.junit.Test; + +import java.util.*; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; + +public class ComparatorsUnitTests { + + @Test + public void isInOrderTest(){ + + List numbers = Arrays.asList(1,2,3,4,4,6,7,8,9,10); + + boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator()); + + Assert.assertTrue(isInAscendingOrder); + } + + @Test + public void isInStrictOrderTest(){ + + List numbers = Arrays.asList(1,2,3,4,3,6,7,8,9,10); + + boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator()); + + Assert.assertFalse(isInAscendingOrder); + } + + + private class AscendingOrderComparator implements Comparator{ + + @Override + public int compare(Integer o1, Integer o2) { + return o1.compareTo(o2); + } + + @Override + public Comparator reversed() { + return null; + } + + @Override + public Comparator thenComparing(Comparator other) { + return null; + } + + @Override + public Comparator thenComparing(Function keyExtractor, Comparator keyComparator) { + return null; + } + + @Override + public > Comparator thenComparing(Function keyExtractor) { + return null; + } + + @Override + public Comparator thenComparingInt(ToIntFunction keyExtractor) { + return null; + } + + @Override + public Comparator thenComparingLong(ToLongFunction keyExtractor) { + return null; + } + + @Override + public Comparator thenComparingDouble(ToDoubleFunction keyExtractor) { + return null; + } + } +} diff --git a/guava21/src/test/java/GauavaStreamsTests.java b/guava21/src/test/java/GauavaStreamsTests.java new file mode 100644 index 0000000000..09e3e29b47 --- /dev/null +++ b/guava21/src/test/java/GauavaStreamsTests.java @@ -0,0 +1,155 @@ +import com.google.common.collect.Streams; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.*; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +public class GauavaStreamsTests { + + List numbers; + + @Before + public void setUp(){ + numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20); + } + + + @Test + public void createStreamsWithCollection(){ + //Deprecated API to create stream from collection + Stream streamFromCollection = Streams.stream(numbers); + + //Assert.assertNotNull(streamFromCollection); + StreamUtility.assertStreamEquals(streamFromCollection, numbers.stream()); + } + + @Test + public void createStreamsWithIterable(){ + Iterable numbersIterable = (Iterable) numbers; + + Stream streamFromIterable = Streams.stream(numbersIterable); + + Assert.assertNotNull(streamFromIterable); + StreamUtility.assertStreamEquals(streamFromIterable, numbers.stream()); + } + + @Test + public void createStreamsWithIterator(){ + Iterator numbersIterator = numbers.iterator(); + + Stream streamFromIterator = Streams.stream(numbersIterator); + + Assert.assertNotNull(streamFromIterator); + StreamUtility.assertStreamEquals(streamFromIterator, numbers.stream()); + } + + @Test + public void createStreamsWithOptional(){ + + Stream streamFromOptional = Streams.stream(Optional.of(1)); + + Assert.assertNotNull(streamFromOptional); + Assert.assertEquals(streamFromOptional.count(), 1); + } + + @Test + public void createStreamsWithOptionalLong(){ + + LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1)); + + Assert.assertNotNull(streamFromOptionalLong); + Assert.assertEquals(streamFromOptionalLong.count(), 1); + } + + @Test + public void createStreamsWithOptionalInt(){ + + IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1)); + + //Assert.assertNotNull(streamFromOptionalInt); + Assert.assertEquals(streamFromOptionalInt.count(), 1); + } + + @Test + public void createStreamsWithOptionalDouble(){ + + DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0)); + + //Assert.assertNotNull(streamFromOptionalDouble); + Assert.assertEquals(streamFromOptionalDouble.count(), 1); + + } + + @Test + public void concatStreamsOfSameType(){ + Stream oddNumbers = Arrays.asList(1,3,5,7,9,11,13,15,17,19).stream(); + Stream evenNumbers = Arrays.asList(2,4,6,8,10,12,14,16,18,20).stream(); + + Stream combinedStreams = Streams.concat(oddNumbers,evenNumbers); + + //Assert.assertNotNull(combinedStreams); + StreamUtility.assertStreamEquals(combinedStreams, Stream.concat(oddNumbers, evenNumbers)); + } + + @Test + public void concatStreamsOfTypeLongStream(){ + LongStream firstTwenty = LongStream.range(1,20); + LongStream nextTwenty = LongStream.range(21,40); + + LongStream combinedStreams = Streams.concat(firstTwenty,nextTwenty); + + Assert.assertNotNull(combinedStreams); + StreamUtility.assertStreamEquals(combinedStreams, LongStream.concat(firstTwenty, nextTwenty)); + } + + @Test + public void concatStreamsOfTypeIntStream(){ + IntStream firstTwenty = IntStream.range(1,20); + IntStream nextTwenty = IntStream.range(21,40); + + IntStream combinedStreams = Streams.concat(firstTwenty,nextTwenty); + + Assert.assertNotNull(combinedStreams); + StreamUtility.assertStreamEquals(combinedStreams, IntStream.concat(firstTwenty, nextTwenty)); + } + + + @Test + public void findLastOfStream(){ + Optional lastElement = Streams.findLast(numbers.stream()); + + Assert.assertNotNull(lastElement.get()); + Assert.assertEquals(lastElement.get(), numbers.get(20)); + } + + @Test + public void mapWithIndexTest(){ + Stream stringSream = Stream.of("a","b","c"); + + Stream mappedStream = Streams.mapWithIndex(stringSream,(str,index) -> str +":"+ index); + + //Assert.assertNotNull(mappedStream); + Assert.assertEquals(mappedStream.findFirst().get(), "a:0"); + + } + + @Test + public void streamsZipTest(){ + Stream stringSream = Stream.of("a","b","c"); + Stream intStream = Stream.of(1,2,3); + Stream mappedStream = Streams.zip(stringSream,intStream, (str,index) -> str +":"+ index); + + //Assert.assertNotNull(mappedStream); + Assert.assertEquals(mappedStream.findFirst().get(), "a:1"); + + } + + + + +} diff --git a/guava21/src/test/java/InternBuilderUnitTests.java b/guava21/src/test/java/InternBuilderUnitTests.java new file mode 100644 index 0000000000..513b44f249 --- /dev/null +++ b/guava21/src/test/java/InternBuilderUnitTests.java @@ -0,0 +1,19 @@ +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import org.junit.Assert; +import org.junit.Test; + +public class InternBuilderUnitTests { + + @Test + public void interBuilderTest(){ + + Interner interners = Interners.newBuilder() + .concurrencyLevel(2) + .strong() + .build(); + + Assert.assertNotNull(interners); + } + +} diff --git a/guava21/src/test/java/MoreCollectorsUnitTests.java b/guava21/src/test/java/MoreCollectorsUnitTests.java new file mode 100644 index 0000000000..956331e25f --- /dev/null +++ b/guava21/src/test/java/MoreCollectorsUnitTests.java @@ -0,0 +1,36 @@ +import com.google.common.collect.MoreCollectors; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class MoreCollectorsUnitTests { + + @Test + public void toOptionalTest(){ + + List numbers = Arrays.asList(1); + + Optional number = numbers.stream() + .map( e -> e*2) + .collect(MoreCollectors.toOptional()); + + Assert.assertEquals(number.get(),new Integer(2)); + } + + + @Test + public void onlyElementTest(){ + List numbers = Arrays.asList(1); + + Integer number = numbers.stream() + .map( e -> e*2) + .collect(MoreCollectors.onlyElement()); + + Assert.assertEquals(number,new Integer(2)); + } + + +} diff --git a/guava21/src/test/java/StreamUtility.java b/guava21/src/test/java/StreamUtility.java new file mode 100644 index 0000000000..91a03be48d --- /dev/null +++ b/guava21/src/test/java/StreamUtility.java @@ -0,0 +1,66 @@ +import org.junit.Assert; + +import java.util.Iterator; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +public class StreamUtility { + + public static boolean assertStreamEquals(Stream stream1, Stream stream2){ + + Iterator iterator1 = stream1.iterator(); + Iterator iterator2 = stream2.iterator(); + + while (iterator1.hasNext()){ + Assert.assertEquals(iterator1.next(), iterator2.next()); + } + + Assert.assertFalse(iterator2.hasNext()); + + return true; + } + + public static boolean assertStreamEquals(LongStream stream1, LongStream stream2) { + + Iterator iterator1 = stream1.iterator(); + Iterator iterator2 = stream2.iterator(); + + while (iterator1.hasNext()){ + Assert.assertEquals(iterator1.next(), iterator2.next()); + } + + Assert.assertFalse(iterator2.hasNext()); + + return true; + } + + public static boolean assertStreamEquals(DoubleStream stream1, DoubleStream stream2) { + + Iterator iterator1 = stream1.iterator(); + Iterator iterator2 = stream2.iterator(); + + while (iterator1.hasNext()){ + Assert.assertEquals(iterator1.next(), iterator2.next()); + } + + Assert.assertFalse(iterator2.hasNext()); + + return true; + } + + public static boolean assertStreamEquals(IntStream stream1, IntStream stream2) { + + Iterator iterator1 = stream1.iterator(); + Iterator iterator2 = stream2.iterator(); + + while (iterator1.hasNext()){ + Assert.assertEquals(iterator1.next(), iterator2.next()); + } + + Assert.assertFalse(iterator2.hasNext()); + + return true; + } +} From 52c1e6a3fbebf2d400d1a5182a26e7c5a99804ff Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 20 Mar 2017 09:18:03 +0100 Subject: [PATCH 148/291] Update README.md --- guava21/README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/guava21/README.md b/guava21/README.md index 8121cf2ea6..ff12555376 100644 --- a/guava21/README.md +++ b/guava21/README.md @@ -1,7 +1 @@ -========= - -## Guava 21 - -**Important**: Guava 21.0 requires Java 8. If you need Java 6, 7 or Android compatibility, use Guava 20.0 for now. Guava 22.0 and on will introduce a Java 6/Android compatible backport of Guava that includes all of the latest changes that don't require Java 8. - -Article 1 : Introduction to Guava21 common.collect package. \ No newline at end of file +## Relevant articles: From 29645fc0d12fdade2cdc03104aa8a04873ca8505 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 20 Mar 2017 12:18:41 +0100 Subject: [PATCH 149/291] BAEL-724 (#1422) Property testing with Javaslang * BAEL-724 add javaslang test and property testing example * BAEL-724 make test more readable * BAEL-724 change missspelled word to the Remainder --- javaslang/pom.xml | 9 +++ .../baeldung/javaslang/PropertyBasedTest.java | 69 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java diff --git a/javaslang/pom.xml b/javaslang/pom.xml index e111132aec..7bb23c0daf 100644 --- a/javaslang/pom.xml +++ b/javaslang/pom.xml @@ -22,8 +22,17 @@ javaslang 2.1.0-alpha + + io.javaslang + javaslang-test + ${javaslang.test.version} + + + 2.0.5 + + diff --git a/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java new file mode 100644 index 0000000000..3acac34550 --- /dev/null +++ b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java @@ -0,0 +1,69 @@ +package com.baeldung.javaslang; + + +import javaslang.CheckedFunction1; +import javaslang.collection.Stream; +import javaslang.test.Arbitrary; +import javaslang.test.CheckResult; +import javaslang.test.Property; +import org.junit.Test; + +public class PropertyBasedTest { + + public Stream stringsSupplier() { + return Stream.from(0).map(i -> { + boolean divByTwo = i % 2 == 0; + boolean divByFive = i % 5 == 0; + + if(divByFive && divByTwo){ + return "DividedByTwoAndFiveWithoutRemainder"; + }else if(divByFive){ + return "DividedByFiveWithoutRemainder"; + }else if(divByTwo){ + return "DividedByTwoWithoutRemainder"; + } + return ""; + }); + } + + @Test + public void givenArbitrarySeq_whenCheckThatEverySecondElementIsEqualToString_thenTestPass() { + //given + Arbitrary multiplesOf2 = Arbitrary.integer() + .filter(i -> i > 0) + .filter(i -> i % 2 == 0 && i % 5 != 0); + + //when + CheckedFunction1 mustEquals = + i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder"); + + + //then + CheckResult result = Property + .def("Every second element must equal to DividedByTwoWithoutRemainder") + .forAll(multiplesOf2) + .suchThat(mustEquals) + .check(10_000, 100); + + result.assertIsSatisfied(); + } + + @Test + public void givenArbitrarySeq_whenCheckThatEveryFifthElementIsEqualToString_thenTestPass() { + //given + Arbitrary multiplesOf5 = Arbitrary.integer() + .filter(i -> i > 0) + .filter(i -> i % 5 == 0 && i % 2 == 0); + + //when + CheckedFunction1 mustEquals = i -> + stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder"); + + //then + Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder") + .forAll(multiplesOf5) + .suchThat(mustEquals) + .check(10_000, 1_000) + .assertIsSatisfied(); + } +} From 5294e7d42587df12774dc50a7304c33d0beea9c8 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Mon, 20 Mar 2017 15:50:43 +0000 Subject: [PATCH 150/291] BAEL-702 - Intro to Vert.x formatting changes --- .../main/java/com/baeldung/HelloVerticle.java | 10 +++---- .../com/baeldung/SimpleServerVerticle.java | 24 ++++++++--------- .../baledung/rest/RestServiceVerticle.java | 26 +++++++++---------- .../com/baeldung/RestServiceVerticleTest.java | 12 ++++----- .../baeldung/SimpleServerVerticleTest.java | 16 ++++++------ 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/vertx/src/main/java/com/baeldung/HelloVerticle.java b/vertx/src/main/java/com/baeldung/HelloVerticle.java index 98d1b336a3..59baceb0d8 100644 --- a/vertx/src/main/java/com/baeldung/HelloVerticle.java +++ b/vertx/src/main/java/com/baeldung/HelloVerticle.java @@ -10,6 +10,11 @@ import io.vertx.core.Vertx; public class HelloVerticle extends AbstractVerticle { private static final Logger LOGGER = LoggerFactory.getLogger(HelloVerticle.class); + public static void main(String[] args) { + Vertx vertx = Vertx.vertx(); + vertx.deployVerticle(new HelloVerticle()); + } + @Override public void start(Future future) { LOGGER.info("Welcome to Vertx"); @@ -19,10 +24,5 @@ public class HelloVerticle extends AbstractVerticle { public void stop() { LOGGER.info("Shutting down application"); } - - public static void main(String[] args) { - Vertx vertx = Vertx.vertx(); - vertx.deployVerticle(new HelloVerticle()); - } } diff --git a/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java index 2cee37903b..6b56896860 100644 --- a/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java +++ b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java @@ -4,21 +4,21 @@ import io.vertx.core.AbstractVerticle; import io.vertx.core.Future; public class SimpleServerVerticle extends AbstractVerticle { - + @Override public void start(Future future) { vertx.createHttpServer() - .requestHandler(request -> { - request.response() - .end("Welcome to Vert.x Intro"); - }) - .listen(config().getInteger("http.port", 8080), result -> { - if (result.succeeded()) { - future.complete(); - } else { - future.fail(result.cause()); - } - }); + .requestHandler(request -> { + request.response() + .end("Welcome to Vert.x Intro"); + }) + .listen(config().getInteger("http.port", 8080), result -> { + if (result.succeeded()) { + future.complete(); + } else { + future.fail(result.cause()); + } + }); } } diff --git a/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java b/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java index 181b3007d5..802f74942e 100644 --- a/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java +++ b/vertx/src/main/java/com/baledung/rest/RestServiceVerticle.java @@ -14,28 +14,28 @@ public class RestServiceVerticle extends AbstractVerticle { Router router = Router.router(vertx); router.get("/api/baeldung/articles/article/:id") - .handler(this::getArticles); + .handler(this::getArticles); vertx.createHttpServer() - .requestHandler(router::accept) - .listen(config().getInteger("http.port", 8080), result -> { - if (result.succeeded()) { - future.complete(); - } else { - future.fail(result.cause()); - } - }); + .requestHandler(router::accept) + .listen(config().getInteger("http.port", 8080), result -> { + if (result.succeeded()) { + future.complete(); + } else { + future.fail(result.cause()); + } + }); } private void getArticles(RoutingContext routingContext) { String articleId = routingContext.request() - .getParam("id"); + .getParam("id"); Article article = new Article(articleId, "This is an intro to vertx", "baeldung", "01-02-2017", 1578); routingContext.response() - .putHeader("content-type", "application/json") - .setStatusCode(200) - .end(Json.encodePrettily(article)); + .putHeader("content-type", "application/json") + .setStatusCode(200) + .end(Json.encodePrettily(article)); } } diff --git a/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java b/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java index 8eebe1396d..b5be0734f4 100644 --- a/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java +++ b/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java @@ -34,13 +34,13 @@ public class RestServiceVerticleTest { final Async async = testContext.async(); vertx.createHttpClient() - .getNow(8080, "localhost", "/api/baeldung/articles/article/12345", response -> { - response.handler(responseBody -> { - testContext.assertTrue(responseBody.toString() - .contains("\"id\" : \"12345\"")); - async.complete(); + .getNow(8080, "localhost", "/api/baeldung/articles/article/12345", response -> { + response.handler(responseBody -> { + testContext.assertTrue(responseBody.toString() + .contains("\"id\" : \"12345\"")); + async.complete(); + }); }); - }); } } diff --git a/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java b/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java index 177f8d8435..189d2f6604 100644 --- a/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java +++ b/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java @@ -20,8 +20,8 @@ public class SimpleServerVerticleTest { public void setup(TestContext testContext) { vertx = Vertx.vertx(); - vertx.deployVerticle(SimpleServerVerticle.class.getName(), - testContext.asyncAssertSuccess()); + vertx.deployVerticle(SimpleServerVerticle.class.getName(), + testContext.asyncAssertSuccess()); } @After @@ -34,13 +34,13 @@ public class SimpleServerVerticleTest { final Async async = testContext.async(); vertx.createHttpClient() - .getNow(8080, "localhost", "/", response -> { - response.handler(responseBody -> { - testContext.assertTrue(responseBody.toString() - .contains("Welcome")); - async.complete(); + .getNow(8080, "localhost", "/", response -> { + response.handler(responseBody -> { + testContext.assertTrue(responseBody.toString() + .contains("Welcome")); + async.complete(); + }); }); - }); } } From b95a014c8ac1c1566d2725c2055a142bfc701b61 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 20 Mar 2017 17:54:02 +0100 Subject: [PATCH 151/291] BAEL-738 (#1456) PUT and PATCH * BAEL-724 code for put/patch article * BAEL-724 fix typo --- .../repository/HeavyResourceRepository.java | 14 +++++ .../controller/HeavyResourceController.java | 31 ++++++++++ .../org/baeldung/web/dto/HeavyResource.java | 62 +++++++++++++++++++ .../HeavyResourceAddressPartialUpdate.java | 31 ++++++++++ .../HeavyResourceControllerTest.java | 57 +++++++++++++++++ 5 files changed, 195 insertions(+) create mode 100644 spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java create mode 100644 spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java create mode 100644 spring-rest/src/main/java/org/baeldung/web/dto/HeavyResource.java create mode 100644 spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressPartialUpdate.java create mode 100644 spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java diff --git a/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java new file mode 100644 index 0000000000..cff78442d0 --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java @@ -0,0 +1,14 @@ +package org.baeldung.repository; + +import org.baeldung.web.dto.HeavyResource; +import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; + +public class HeavyResourceRepository { + + public void save(HeavyResource heavyResource) { + } + + public void save(HeavyResourceAddressPartialUpdate partialUpdate) { + + } +} diff --git a/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java new file mode 100644 index 0000000000..a2d5cfbd7b --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java @@ -0,0 +1,31 @@ +package org.baeldung.web.controller; + + +import org.baeldung.repository.HeavyResourceRepository; +import org.baeldung.web.dto.HeavyResource; +import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HeavyResourceController { + + private HeavyResourceRepository heavyResourceRepository = new HeavyResourceRepository(); + + @RequestMapping(value = "/heavy", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity saveResource(@RequestBody HeavyResource heavyResource) { + heavyResourceRepository.save(heavyResource); + return ResponseEntity.ok("resource saved"); + } + + @RequestMapping(value = "/heavy", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity partialUpdateName(@RequestBody HeavyResourceAddressPartialUpdate partialUpdate) { + heavyResourceRepository.save(partialUpdate); + return ResponseEntity.ok("resource address updated"); + } + +} diff --git a/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResource.java b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResource.java new file mode 100644 index 0000000000..934e76606f --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResource.java @@ -0,0 +1,62 @@ +package org.baeldung.web.dto; + + +public class HeavyResource { + private Integer id; + private String name; + private String surname; + private Integer age; + private String address; + + + public HeavyResource() { + } + + public HeavyResource(Integer id, String name, String surname, Integer age, String address) { + this.id = id; + this.name = name; + this.surname = surname; + this.age = age; + this.address = address; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressPartialUpdate.java b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressPartialUpdate.java new file mode 100644 index 0000000000..f90f02ea08 --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressPartialUpdate.java @@ -0,0 +1,31 @@ +package org.baeldung.web.dto; + + +public class HeavyResourceAddressPartialUpdate { + private Integer id; + private String address; + + public HeavyResourceAddressPartialUpdate() { + } + + public HeavyResourceAddressPartialUpdate(Integer id, String address) { + this.id = id; + this.address = address; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java new file mode 100644 index 0000000000..e68506701d --- /dev/null +++ b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java @@ -0,0 +1,57 @@ +package org.baeldung.web.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.baeldung.config.WebConfig; +import org.baeldung.web.dto.HeavyResource; +import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = WebConfig.class) +@WebAppConfiguration +public class HeavyResourceControllerTest { + + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext webApplicationContext; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Before + public void setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + public void givenHeavyResource_whenSendPutRequest_thenCreateResource() throws Exception { + mockMvc.perform(put("/heavy") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(objectMapper.writeValueAsString(new HeavyResource(1, "Tom", "Jackson", 12, "heaven street"))) + ).andExpect(status().isOk()); + } + + @Test + public void givenNewAddressOfResource_whenExecutePutRequest_thenUpdateResourcePartially() throws Exception { + mockMvc.perform(patch("/heavy") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(objectMapper.writeValueAsString(new HeavyResourceAddressPartialUpdate(1, "5th avenue"))) + ).andExpect(status().isOk()); + } + +} \ No newline at end of file From 9c755ee39c9401f32c3592f9dc664e84a6669aad Mon Sep 17 00:00:00 2001 From: Yasin Date: Mon, 20 Mar 2017 23:43:42 +0530 Subject: [PATCH 152/291] BAEL-722 Intro to JSONassert (#1460) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements * BAEL-718 Quick intro to javatuples * merging pom from master * BAEL-722 Intro to JSONassert * BAEL-722 Intro to JSONassert Updated to 1.5.0 --- libraries/pom.xml | 2 +- .../com/baeldung/jsonassert/JsonAssertTest.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/pom.xml b/libraries/pom.xml index 85c777b12c..71d0e76c8a 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -77,7 +77,7 @@ 1.2 3.21.0-GA 3.6.2 - 1.4.0 + 1.5.0 \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java b/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java index c169d83897..b70703cc08 100644 --- a/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java +++ b/libraries/src/test/java/com/baeldung/jsonassert/JsonAssertTest.java @@ -1,5 +1,8 @@ package com.baeldung.jsonassert; + +import static org.assertj.core.api.Assertions.assertThat; + import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; @@ -64,6 +67,17 @@ public class JsonAssertTest { JSONAssert.assertEquals("{id:1,name:\"Juergen\", address:{city:\"Hollywood\", " + "state:\"LA\", zip:91601}}", result, false); } + + @Test + public void whenMessageUsedInAssertion_thenDisplayMessageOnFailure() throws JSONException { + String actual = "{id:123,name:\"John\"}"; + String failureMessage = "Only one field is expected: name"; + try { + JSONAssert.assertEquals(failureMessage, "{name:\"John\"}", actual, JSONCompareMode.STRICT); + } catch (AssertionError ae) { + assertThat(ae.getMessage()).containsIgnoringCase(failureMessage); + } + } @Test public void givenArray_whenComparing_thenOrderMustMatchForStrict() throws JSONException { From b5ef48a1d88085e13e57814edd0b03b296d37e98 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Tue, 21 Mar 2017 10:00:35 +0100 Subject: [PATCH 153/291] Turn off spring-5 module --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d68a7d0749..e0556a7c50 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ handling-spring-static-resources hazelcast - + httpclient hystrix @@ -110,7 +110,7 @@ selenium-junit-testng solr-fulltext-search spark-java - spring-5 + spring-akka spring-amqp spring-all From 07c0e84bf47466dd76eaa3ab3b4c649caf264f04 Mon Sep 17 00:00:00 2001 From: Parth Joshi Date: Tue, 21 Mar 2017 15:54:57 +0530 Subject: [PATCH 154/291] Initial commit for merging modules spring-mvc-forms into (#1222) spring-mvc-simple. --- spring-mvc-forms/README.md | 1 + spring-mvc-simple/pom.xml | 35 ++++++++++++ .../ApplicationConfiguration.java | 37 +++++++++++++ .../spring/configuration/WebInitializer.java | 48 +++++++++++++++++ .../spring/controller/CustomerController.java | 42 +++++++++++++++ .../spring/controller/EmployeeController.java | 47 ++++++++++++++++ .../controller/FileUploadController.java | 52 ++++++++++++++++++ .../com/baeldung/spring/domain/Customer.java | 45 ++++++++++++++++ .../com/baeldung/spring/domain/Employee.java | 46 ++++++++++++++++ .../FileUploadExceptionAdvice.java | 19 +++++++ .../spring/validator/CustomerValidator.java | 28 ++++++++++ ...servlet_AnnotationMethodHandlerAdapter.xml | 50 ++++++++--------- ...g-servlet_RequestMappingHandlerAdapter.xml | 54 +++++++++---------- ...servlet_SimpleControllerHandlerAdapter.xml | 48 ++++++++--------- .../src/main/webapp/WEB-INF/Greeting.jsp | 9 ++-- .../main/webapp/WEB-INF/views/Greeting.jsp | 5 ++ .../webapp/WEB-INF/views/customerHome.jsp | 47 ++++++++++++++++ .../webapp/WEB-INF/views/customerView.jsp | 28 ++++++++++ .../webapp/WEB-INF/views/employeeHome.jsp | 33 ++++++++++++ .../webapp/WEB-INF/views/employeeView.jsp | 24 +++++++++ .../src/main/webapp/WEB-INF/views/error.jsp | 20 +++++++ .../src/main/webapp/WEB-INF/views/file.jsp | 23 ++++++++ 22 files changed, 661 insertions(+), 80 deletions(-) create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/controller/CustomerController.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/controller/EmployeeController.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Customer.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Employee.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/interceptor/FileUploadExceptionAdvice.java create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/validator/CustomerValidator.java create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/Greeting.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/customerHome.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/customerView.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeHome.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeView.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/error.jsp create mode 100644 spring-mvc-simple/src/main/webapp/WEB-INF/views/file.jsp diff --git a/spring-mvc-forms/README.md b/spring-mvc-forms/README.md index 51dbef9856..745851a102 100644 --- a/spring-mvc-forms/README.md +++ b/spring-mvc-forms/README.md @@ -2,3 +2,4 @@ ### Relevant Articles - [MaxUploadSizeExceededException in Spring](http://www.baeldung.com/spring-maxuploadsizeexceeded) +- [Getting Started with Forms in Spring MVC](http://www.baeldung.com/spring-mvc-form-tutorial) diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml index 4ab5bd9d1e..a004eae4d9 100644 --- a/spring-mvc-simple/pom.xml +++ b/spring-mvc-simple/pom.xml @@ -12,6 +12,13 @@ 4.3.4.RELEASE 3.5.1 2.6 + 1.2 + 2.3.1 + 3.1.0 + 1.8 + 5.3.3.Final + enter-location-of-server + 1.3.2 @@ -40,6 +47,33 @@ spring-core ${springframework.version} + + javax.servlet.jsp + javax.servlet.jsp-api + ${javax.servlet.jsp-api.version} + + + + javax.servlet + jstl + ${jstl.version} + + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + org.springframework + spring-webmvc + ${springframework.version} + + + commons-fileupload + commons-fileupload + ${fileupload.version} + @@ -61,6 +95,7 @@ src/main/webapp springMvcSimple false + ${deploy-path} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java new file mode 100644 index 0000000000..9ace968bbe --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "com.baeldung.springmvcforms") +class ApplicationConfiguration extends WebMvcConfigurerAdapter { + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + @Bean + public InternalResourceViewResolver jspViewResolver() { + InternalResourceViewResolver bean = new InternalResourceViewResolver(); + bean.setPrefix("/WEB-INF/views/"); + bean.setSuffix(".jsp"); + return bean; + } + + @Bean + public MultipartResolver multipartResolver() { + CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); + multipartResolver.setMaxUploadSize(5242880); + return multipartResolver; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java new file mode 100644 index 0000000000..d6bbf5eabd --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java @@ -0,0 +1,48 @@ +package com.baeldung.spring.configuration; + +import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.ContextLoaderListener; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +public class WebInitializer implements WebApplicationInitializer { + + public void onStartup(ServletContext container) throws ServletException { + + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.register(ApplicationConfiguration.class); + ctx.setServletContext(container); + + // Manage the lifecycle of the root application context + container.addListener(new ContextLoaderListener(ctx)); + + ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx)); + + servlet.setLoadOnStartup(1); + servlet.addMapping("/"); + + } +// @Override +// public void onStartup(ServletContext container) { +// // Create the 'root' Spring application context +// AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); +// rootContext.register(ServiceConfig.class, JPAConfig.class, SecurityConfig.class); +// +// // Manage the lifecycle of the root application context +// container.addListener(new ContextLoaderListener(rootContext)); +// +// // Create the dispatcher servlet's Spring application context +// AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext(); +// dispatcherServlet.register(MvcConfig.class); +// +// // Register and map the dispatcher servlet +// ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet)); +// dispatcher.setLoadOnStartup(1); +// dispatcher.addMapping("/"); +// +// } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/CustomerController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/CustomerController.java new file mode 100644 index 0000000000..8ecfce58e3 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/CustomerController.java @@ -0,0 +1,42 @@ +package com.baeldung.spring.controller; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.ModelAndView; + +import com.baeldung.spring.domain.Customer; +import com.baeldung.spring.validator.CustomerValidator; + +@Controller +public class CustomerController { + + @Autowired + CustomerValidator validator; + + @RequestMapping(value = "/customer", method = RequestMethod.GET) + public ModelAndView showForm() { + return new ModelAndView("customerHome", "customer", new Customer()); + } + + @PostMapping("/addCustomer") + public String submit(@Valid @ModelAttribute("customer") final Customer customer, final BindingResult result, final ModelMap model) { + validator.validate(customer, result); + if (result.hasErrors()) { + return "customerHome"; + } + model.addAttribute("customerId", customer.getCustomerId()); + model.addAttribute("customerName", customer.getCustomerName()); + model.addAttribute("customerContact", customer.getCustomerContact()); + model.addAttribute("customerEmail", customer.getCustomerEmail()); + return "customerView"; + } + +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/EmployeeController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/EmployeeController.java new file mode 100644 index 0000000000..6543a98af1 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/EmployeeController.java @@ -0,0 +1,47 @@ +package com.baeldung.spring.controller; + +import java.util.HashMap; +import java.util.Map; + +import javax.validation.Valid; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import com.baeldung.spring.domain.Employee; + +@Controller +public class EmployeeController { + + Map employeeMap = new HashMap<>(); + + @RequestMapping(value = "/employee", method = RequestMethod.GET) + public ModelAndView showForm() { + return new ModelAndView("employeeHome", "employee", new Employee()); + } + + @RequestMapping(value = "/employee/{Id}", produces = { "application/json", "application/xml" }, method = RequestMethod.GET) + public @ResponseBody Employee getEmployeeById(@PathVariable final long Id) { + return employeeMap.get(Id); + } + + @RequestMapping(value = "/addEmployee", method = RequestMethod.POST) + public String submit(@Valid @ModelAttribute("employee") final Employee employee, final BindingResult result, final ModelMap model) { + if (result.hasErrors()) { + return "error"; + } + model.addAttribute("name", employee.getName()); + model.addAttribute("contactNumber", employee.getContactNumber()); + model.addAttribute("id", employee.getId()); + employeeMap.put(employee.getId(), employee); + return "employeeView"; + } + +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java new file mode 100644 index 0000000000..47af2ab50d --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java @@ -0,0 +1,52 @@ +package com.baeldung.spring.controller; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +@Controller +public class FileUploadController implements HandlerExceptionResolver { + + @RequestMapping(value = "/uploadFile", method = RequestMethod.GET) + public String getImageView() { + return "file"; + } + + @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) + public ModelAndView uploadFile(MultipartFile file) throws IOException{ + ModelAndView modelAndView = new ModelAndView("file"); + + InputStream in = file.getInputStream(); + File currDir = new File("."); + String path = currDir.getAbsolutePath(); + FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ file.getOriginalFilename()); + int ch = 0; + while ((ch = in.read()) != -1) { + f.write(ch); + } + f.flush(); + f.close(); + + modelAndView.getModel().put("message", "File uploaded successfully!"); + return modelAndView; + } + + @Override + public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exc) { + ModelAndView modelAndView = new ModelAndView("file"); + if (exc instanceof MaxUploadSizeExceededException) { + modelAndView.getModel().put("message", "File size exceeds limit!"); + } + return modelAndView; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Customer.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Customer.java new file mode 100644 index 0000000000..09322105f8 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Customer.java @@ -0,0 +1,45 @@ +package com.baeldung.spring.domain; + +public class Customer { + private String customerId; + private String customerName; + private String customerContact; + private String customerEmail; + + public Customer() { + super(); + } + + public String getCustomerId() { + return customerId; + } + + public void setCustomerId(String customerId) { + this.customerId = customerId; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public String getCustomerContact() { + return customerContact; + } + + public void setCustomerContact(String customerContact) { + this.customerContact = customerContact; + } + + public String getCustomerEmail() { + return customerEmail; + } + + public void setCustomerEmail(String customerEmail) { + this.customerEmail = customerEmail; + } + +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Employee.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Employee.java new file mode 100644 index 0000000000..900770b873 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/domain/Employee.java @@ -0,0 +1,46 @@ +package com.baeldung.spring.domain; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +public class Employee { + + private long id; + + @NotNull + @Size(min = 5) + private String name; + + @NotNull + @Size(min = 7) + private String contactNumber; + + public Employee() { + super(); + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(final long id) { + this.id = id; + } + + public String getContactNumber() { + return contactNumber; + } + + public void setContactNumber(final String contactNumber) { + this.contactNumber = contactNumber; + } + +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/interceptor/FileUploadExceptionAdvice.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/interceptor/FileUploadExceptionAdvice.java new file mode 100644 index 0000000000..2f3c44cf12 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/interceptor/FileUploadExceptionAdvice.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.interceptor; + +import org.springframework.web.servlet.ModelAndView; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class FileUploadExceptionAdvice { + + @ExceptionHandler(MaxUploadSizeExceededException.class) + public ModelAndView handleMaxSizeException(MaxUploadSizeExceededException exc, HttpServletRequest request, HttpServletResponse response){ + ModelAndView modelAndView = new ModelAndView("file"); + modelAndView.getModel().put("message", "File too large!"); + return modelAndView; + } +} \ No newline at end of file diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/validator/CustomerValidator.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/validator/CustomerValidator.java new file mode 100644 index 0000000000..2515e8d31f --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/validator/CustomerValidator.java @@ -0,0 +1,28 @@ +package com.baeldung.spring.validator; + +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +import com.baeldung.spring.domain.Customer; + +@Component +public class CustomerValidator implements Validator { + + @Override + public boolean supports(Class clazz) { + return Customer.class.isAssignableFrom(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "customerId", "error.customerId", "Customer Id is required."); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "customerName", "error.customerName", "Customer Name is required."); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "customerContact", "error.customerNumber", "Customer Contact is required."); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "customerEmail", "error.customerEmail", "Customer Email is required."); + + } + +} diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml index a8071a622f..430b849012 100644 --- a/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml +++ b/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml @@ -1,26 +1,26 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml index b32a213eb3..d3783c2e67 100644 --- a/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml +++ b/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml @@ -1,28 +1,28 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml index 60c9b9e3df..1d6e5628df 100644 --- a/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml +++ b/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml @@ -1,25 +1,25 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/Greeting.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/Greeting.jsp index 820d2f380f..7f7fbccccd 100644 --- a/spring-mvc-simple/src/main/webapp/WEB-INF/Greeting.jsp +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/Greeting.jsp @@ -1,5 +1,6 @@ - - -

Hello ${message}

- + + +

Hello ${message}

+ + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/Greeting.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/Greeting.jsp new file mode 100644 index 0000000000..efd48179f9 --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/Greeting.jsp @@ -0,0 +1,5 @@ + + +

Hello ${message}

+ + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerHome.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerHome.jsp new file mode 100644 index 0000000000..df34a47cc0 --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerHome.jsp @@ -0,0 +1,47 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> + + + +Form Example - Add Customer + + + +

Welcome, Enter The Customer Details

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Customer Id
Customer Name
Customer Contact
Customer Email
+
+ + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerView.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerView.jsp new file mode 100644 index 0000000000..ab2631bd02 --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/customerView.jsp @@ -0,0 +1,28 @@ +<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> + + +Spring MVC Form Handling + + + +

Submitted Customer Information

+ + + + + + + + + + + + + + + + + +
Customer Id :${customerId}
Customer Name :${customerName}
Customer Contact :${customerContact}
Customer Email :${customerEmail}
+ + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeHome.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeHome.jsp new file mode 100644 index 0000000000..5ed572000a --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeHome.jsp @@ -0,0 +1,33 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> + + + +Form Example - Register an Employee + + +

Welcome, Enter The Employee Details

+ + + + + + + + + + + + + + + + + + +
Name
Id
Contact Number
+
+ + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeView.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeView.jsp new file mode 100644 index 0000000000..1457bc5fc8 --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/employeeView.jsp @@ -0,0 +1,24 @@ +<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> + + +Spring MVC Form Handling + + + +

Submitted Employee Information

+ + + + + + + + + + + + + +
Name :${name}
ID :${id}
Contact Number :${contactNumber}
+ + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/error.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/error.jsp new file mode 100644 index 0000000000..8f3d83af17 --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/error.jsp @@ -0,0 +1,20 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +SpringMVCExample + + + +

Pleas enter the correct details

+ + + + +
Retry
+ + + + \ No newline at end of file diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/file.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/file.jsp new file mode 100644 index 0000000000..0ed8dae5ed --- /dev/null +++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/file.jsp @@ -0,0 +1,23 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + +Upload file + + + +
+ + +
+
+${message } +

+
+ +
+ + \ No newline at end of file From 78f87104d66ae0f9d01ba052e58c02cdbec6973f Mon Sep 17 00:00:00 2001 From: Felipe Reis Date: Tue, 21 Mar 2017 08:23:41 -0300 Subject: [PATCH 155/291] BAEL-137 Intro do JHipster (#1427) * refactor: Reorder tests without lambda Moves inner implementations of Answer and ArgumentMatcher to the top of the test classes. Also changes the lambda expression to a regular "pre java 8" expression in one of the tests. Resolves: BAEL-632 * feat: Create basic Monolithic JHipster project Commit just after creating a JHipster project, before making any modifications. Resolves: BAEL-137 * chore: Change the artifactId and name of the project From baeldung to jhipster-monolithic and JHipster Monolithic Application Relates to: BAEL-137 * feat: Create entities Post and Comment Relates to: BAEL-137 * feat: Fix Gatling configuration in pom.xml Relates to: BAEL-137 * feat: Add files for Continuous Integration Relates to: BAEL-137 * feat: Change pom.xml to conform to Baeldung standards - moved the element to the bottom of the file - excluded integration tests in the default surefire configuration - added a new profile, called integration, and added the integration tests there - added Java 8 in the and tags, under maven-compiler solves: BAEL-137 * chore: Add jhipster module to parent pom --- jhipster/.editorconfig | 24 + jhipster/.gitattributes | 22 + jhipster/.gitignore | 143 +++ jhipster/.gitlab-ci.yml | 56 + jhipster/.jhipster/Comment.json | 39 + jhipster/.jhipster/Post.json | 52 + jhipster/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 49502 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + jhipster/.travis.yml | 41 + jhipster/.yo-rc.json | 36 + jhipster/Jenkinsfile | 50 + jhipster/README.md | 153 +++ jhipster/angular-cli.json | 55 + jhipster/circle.yml | 25 + jhipster/mvnw | 233 ++++ jhipster/mvnw.cmd | 145 +++ jhipster/package.json | 112 ++ jhipster/pom.xml | 1034 +++++++++++++++++ jhipster/postcss.config.js | 3 + jhipster/src/main/docker/Dockerfile | 13 + jhipster/src/main/docker/app.yml | 14 + jhipster/src/main/docker/mysql.yml | 13 + jhipster/src/main/docker/sonar.yml | 7 + .../java/com/baeldung/ApplicationWebXml.java | 21 + .../main/java/com/baeldung/BaeldungApp.java | 84 ++ .../baeldung/aop/logging/LoggingAspect.java | 79 ++ .../config/ApplicationProperties.java | 15 + .../baeldung/config/AsyncConfiguration.java | 46 + .../baeldung/config/CacheConfiguration.java | 48 + .../config/CloudDatabaseConfiguration.java | 23 + .../java/com/baeldung/config/Constants.java | 16 + .../config/DatabaseConfiguration.java | 75 ++ .../config/DateTimeFormatConfiguration.java | 17 + .../baeldung/config/DefaultProfileUtil.java | 48 + .../baeldung/config/LocaleConfiguration.java | 35 + .../config/LoggingAspectConfiguration.java | 19 + .../baeldung/config/LoggingConfiguration.java | 109 ++ .../baeldung/config/MetricsConfiguration.java | 94 ++ .../config/SecurityConfiguration.java | 127 ++ .../config/ThymeleafConfiguration.java | 26 + .../com/baeldung/config/WebConfigurer.java | 186 +++ .../config/audit/AuditEventConverter.java | 91 ++ .../baeldung/config/audit/package-info.java | 4 + .../com/baeldung/config/package-info.java | 4 + .../domain/AbstractAuditingEntity.java | 80 ++ .../java/com/baeldung/domain/Authority.java | 66 ++ .../java/com/baeldung/domain/Comment.java | 114 ++ .../baeldung/domain/PersistentAuditEvent.java | 78 ++ .../main/java/com/baeldung/domain/Post.java | 133 +++ .../main/java/com/baeldung/domain/User.java | 235 ++++ .../com/baeldung/domain/package-info.java | 4 + .../repository/AuthorityRepository.java | 11 + .../repository/CommentRepository.java | 15 + .../CustomAuditEventRepository.java | 81 ++ .../PersistenceAuditEventRepository.java | 26 + .../baeldung/repository/PostRepository.java | 18 + .../baeldung/repository/UserRepository.java | 37 + .../com/baeldung/repository/package-info.java | 4 + .../security/AuthoritiesConstants.java | 16 + .../security/DomainUserDetailsService.java | 51 + .../com/baeldung/security/SecurityUtils.java | 68 ++ .../security/SpringSecurityAuditorAware.java | 19 + .../security/UserNotActivatedException.java | 19 + .../baeldung/security/jwt/JWTConfigurer.java | 23 + .../com/baeldung/security/jwt/JWTFilter.java | 58 + .../baeldung/security/jwt/TokenProvider.java | 109 ++ .../com/baeldung/security/package-info.java | 4 + .../baeldung/service/AuditEventService.java | 50 + .../com/baeldung/service/MailService.java | 108 ++ .../com/baeldung/service/UserService.java | 228 ++++ .../com/baeldung/service/dto/UserDTO.java | 167 +++ .../baeldung/service/dto/package-info.java | 4 + .../baeldung/service/mapper/UserMapper.java | 55 + .../baeldung/service/mapper/package-info.java | 4 + .../com/baeldung/service/package-info.java | 4 + .../com/baeldung/service/util/RandomUtil.java | 41 + .../baeldung/web/rest/AccountResource.java | 202 ++++ .../com/baeldung/web/rest/AuditResource.java | 76 ++ .../baeldung/web/rest/CommentResource.java | 129 ++ .../java/com/baeldung/web/rest/JWTToken.java | 24 + .../com/baeldung/web/rest/LogsResource.java | 39 + .../com/baeldung/web/rest/PostResource.java | 129 ++ .../web/rest/ProfileInfoResource.java | 69 ++ .../baeldung/web/rest/UserJWTController.java | 60 + .../com/baeldung/web/rest/UserResource.java | 187 +++ .../errors/CustomParameterizedException.java | 34 + .../web/rest/errors/ErrorConstants.java | 14 + .../com/baeldung/web/rest/errors/ErrorVM.java | 52 + .../web/rest/errors/ExceptionTranslator.java | 85 ++ .../web/rest/errors/FieldErrorVM.java | 33 + .../web/rest/errors/ParameterizedErrorVM.java | 27 + .../com/baeldung/web/rest/package-info.java | 4 + .../baeldung/web/rest/util/HeaderUtil.java | 45 + .../web/rest/util/PaginationUtil.java | 47 + .../web/rest/vm/KeyAndPasswordVM.java | 27 + .../com/baeldung/web/rest/vm/LoggerVM.java | 48 + .../com/baeldung/web/rest/vm/LoginVM.java | 55 + .../baeldung/web/rest/vm/ManagedUserVM.java | 45 + .../baeldung/web/rest/vm/package-info.java | 4 + .../src/main/resources/.h2.server.properties | 5 + jhipster/src/main/resources/banner.txt | 10 + .../main/resources/config/application-dev.yml | 130 +++ .../resources/config/application-prod.yml | 132 +++ .../src/main/resources/config/application.yml | 106 ++ .../config/liquibase/authorities.csv | 3 + .../00000000000000_initial_schema.xml | 149 +++ .../20170316223211_added_entity_Post.xml | 45 + ...16223211_added_entity_constraints_Post.xml | 18 + .../20170316224021_added_entity_Comment.xml | 41 + ...24021_added_entity_constraints_Comment.xml | 18 + .../resources/config/liquibase/master.xml | 14 + .../main/resources/config/liquibase/users.csv | 5 + .../config/liquibase/users_authorities.csv | 6 + .../main/resources/i18n/messages.properties | 22 + .../resources/i18n/messages_en.properties | 22 + .../src/main/resources/logback-spring.xml | 66 ++ .../main/resources/mails/activationEmail.html | 24 + .../main/resources/mails/creationEmail.html | 24 + .../resources/mails/passwordResetEmail.html | 24 + .../src/main/resources/templates/error.html | 162 +++ jhipster/src/main/webapp/404.html | 60 + .../main/webapp/app/account/account.module.ts | 45 + .../main/webapp/app/account/account.route.ts | 26 + .../account/activate/activate.component.html | 19 + .../account/activate/activate.component.ts | 42 + .../app/account/activate/activate.route.ts | 14 + .../app/account/activate/activate.service.ts | 18 + jhipster/src/main/webapp/app/account/index.ts | 19 + .../password-reset-finish.component.html | 77 ++ .../finish/password-reset-finish.component.ts | 65 ++ .../finish/password-reset-finish.route.ts | 14 + .../finish/password-reset-finish.service.ts | 13 + .../init/password-reset-init.component.html | 47 + .../init/password-reset-init.component.ts | 49 + .../init/password-reset-init.route.ts | 14 + .../init/password-reset-init.service.ts | 13 + .../password-strength-bar.component.ts | 89 ++ .../password/password-strength-bar.scss | 23 + .../account/password/password.component.html | 65 ++ .../account/password/password.component.ts | 49 + .../app/account/password/password.route.ts | 14 + .../app/account/password/password.service.ts | 13 + .../account/register/register.component.html | 122 ++ .../account/register/register.component.ts | 73 ++ .../app/account/register/register.route.ts | 14 + .../app/account/register/register.service.ts | 13 + .../account/settings/settings.component.html | 86 ++ .../account/settings/settings.component.ts | 63 + .../app/account/settings/settings.route.ts | 14 + .../src/main/webapp/app/admin/admin.module.ts | 73 ++ .../src/main/webapp/app/admin/admin.route.ts | 36 + .../app/admin/audits/audit-data.model.ts | 6 + .../webapp/app/admin/audits/audit.model.ts | 10 + .../app/admin/audits/audits.component.html | 45 + .../app/admin/audits/audits.component.ts | 99 ++ .../webapp/app/admin/audits/audits.route.ts | 12 + .../webapp/app/admin/audits/audits.service.ts | 23 + .../configuration.component.html | 46 + .../configuration/configuration.component.ts | 48 + .../configuration/configuration.route.ts | 12 + .../configuration/configuration.service.ts | 53 + .../webapp/app/admin/docs/docs.component.html | 2 + .../webapp/app/admin/docs/docs.component.ts | 14 + .../main/webapp/app/admin/docs/docs.route.ts | 12 + .../admin/health/health-modal.component.html | 36 + .../admin/health/health-modal.component.ts | 37 + .../app/admin/health/health.component.html | 34 + .../app/admin/health/health.component.ts | 69 ++ .../webapp/app/admin/health/health.route.ts | 12 + .../webapp/app/admin/health/health.service.ts | 140 +++ jhipster/src/main/webapp/app/admin/index.ts | 29 + .../main/webapp/app/admin/logs/log.model.ts | 6 + .../webapp/app/admin/logs/logs.component.html | 27 + .../webapp/app/admin/logs/logs.component.ts | 38 + .../main/webapp/app/admin/logs/logs.route.ts | 12 + .../webapp/app/admin/logs/logs.service.ts | 18 + .../metrics/metrics-modal.component.html | 56 + .../admin/metrics/metrics-modal.component.ts | 48 + .../app/admin/metrics/metrics.component.html | 253 ++++ .../app/admin/metrics/metrics.component.ts | 74 ++ .../webapp/app/admin/metrics/metrics.route.ts | 12 + .../app/admin/metrics/metrics.service.ts | 17 + ...er-management-delete-dialog.component.html | 19 + ...user-management-delete-dialog.component.ts | 63 + .../user-management-detail.component.html | 44 + .../user-management-detail.component.ts | 40 + .../user-management-dialog.component.html | 112 ++ .../user-management-dialog.component.ts | 89 ++ .../user-management.component.html | 81 ++ .../user-management.component.ts | 131 +++ .../user-management/user-management.route.ts | 77 ++ .../user-management/user-modal.service.ts | 42 + jhipster/src/main/webapp/app/app.constants.ts | 7 + jhipster/src/main/webapp/app/app.main.ts | 11 + jhipster/src/main/webapp/app/app.module.ts | 58 + jhipster/src/main/webapp/app/app.route.ts | 9 + .../webapp/app/blocks/config/prod.config.ts | 9 + .../blocks/config/uib-pagination.config.ts | 13 + .../interceptor/auth-expired.interceptor.ts | 34 + .../blocks/interceptor/auth.interceptor.ts | 27 + .../interceptor/errorhandler.interceptor.ts | 24 + .../app/blocks/interceptor/http.provider.ts | 45 + .../interceptor/notification.interceptor.ts | 33 + .../comment-delete-dialog.component.html | 19 + .../comment-delete-dialog.component.ts | 67 ++ .../comment/comment-detail.component.html | 35 + .../comment/comment-detail.component.ts | 43 + .../comment/comment-dialog.component.html | 76 ++ .../comment/comment-dialog.component.ts | 107 ++ .../entities/comment/comment-popup.service.ts | 50 + .../entities/comment/comment.component.html | 64 + .../app/entities/comment/comment.component.ts | 110 ++ .../app/entities/comment/comment.model.ts | 10 + .../app/entities/comment/comment.module.ts | 50 + .../app/entities/comment/comment.route.ts | 61 + .../app/entities/comment/comment.service.ts | 78 ++ .../main/webapp/app/entities/comment/index.ts | 8 + .../main/webapp/app/entities/entity.module.ts | 18 + .../main/webapp/app/entities/post/index.ts | 8 + .../post/post-delete-dialog.component.html | 19 + .../post/post-delete-dialog.component.ts | 67 ++ .../entities/post/post-detail.component.html | 37 + .../entities/post/post-detail.component.ts | 43 + .../entities/post/post-dialog.component.html | 96 ++ .../entities/post/post-dialog.component.ts | 107 ++ .../app/entities/post/post-popup.service.ts | 50 + .../app/entities/post/post.component.html | 64 + .../app/entities/post/post.component.ts | 110 ++ .../webapp/app/entities/post/post.model.ts | 11 + .../webapp/app/entities/post/post.module.ts | 52 + .../webapp/app/entities/post/post.route.ts | 61 + .../webapp/app/entities/post/post.service.ts | 78 ++ .../main/webapp/app/home/home.component.html | 42 + .../main/webapp/app/home/home.component.ts | 50 + .../src/main/webapp/app/home/home.module.ts | 23 + .../src/main/webapp/app/home/home.route.ts | 14 + jhipster/src/main/webapp/app/home/home.scss | 26 + jhipster/src/main/webapp/app/home/index.ts | 3 + .../app/layouts/error/error.component.html | 17 + .../app/layouts/error/error.component.ts | 20 + .../webapp/app/layouts/error/error.route.ts | 25 + .../app/layouts/footer/footer.component.html | 4 + .../app/layouts/footer/footer.component.ts | 7 + jhipster/src/main/webapp/app/layouts/index.ts | 10 + .../app/layouts/layout-routing.module.ts | 20 + .../app/layouts/main/main.component.html | 11 + .../webapp/app/layouts/main/main.component.ts | 47 + .../layouts/navbar/active-menu.directive.ts | 26 + .../app/layouts/navbar/navbar.component.html | 168 +++ .../app/layouts/navbar/navbar.component.ts | 81 ++ .../webapp/app/layouts/navbar/navbar.scss | 70 ++ .../layouts/profiles/page-ribbon.component.ts | 25 + .../app/layouts/profiles/page-ribbon.scss | 32 + .../layouts/profiles/profile-info.model.ts | 6 + .../app/layouts/profiles/profile.service.ts | 26 + jhipster/src/main/webapp/app/polyfills.ts | 3 + .../app/shared/alert/alert-error.component.ts | 101 ++ .../app/shared/alert/alert.component.ts | 26 + .../webapp/app/shared/auth/account.service.ts | 16 + .../app/shared/auth/auth-jwt.service.ts | 61 + .../webapp/app/shared/auth/auth.service.ts | 65 ++ .../webapp/app/shared/auth/csrf.service.ts | 13 + .../auth/has-any-authority.directive.ts | 42 + .../app/shared/auth/principal.service.ts | 93 ++ .../app/shared/auth/state-storage.service.ts | 40 + .../shared/auth/user-route-access-service.ts | 15 + .../shared/constants/pagination.constants.ts | 1 + jhipster/src/main/webapp/app/shared/index.ts | 23 + .../app/shared/language/language.constants.ts | 8 + .../app/shared/language/language.helper.ts | 53 + .../app/shared/language/language.pipe.ts | 42 + .../app/shared/login/login-modal.service.ts | 26 + .../app/shared/login/login.component.html | 46 + .../app/shared/login/login.component.ts | 90 ++ .../webapp/app/shared/login/login.service.ts | 45 + .../webapp/app/shared/shared-common.module.ts | 47 + .../webapp/app/shared/shared-libs.module.ts | 27 + .../main/webapp/app/shared/shared.module.ts | 53 + .../webapp/app/shared/user/account.model.ts | 12 + .../main/webapp/app/shared/user/user.model.ts | 44 + .../webapp/app/shared/user/user.service.ts | 45 + jhipster/src/main/webapp/app/vendor.ts | 3 + .../main/webapp/content/images/hipster.png | Bin 0 -> 9499 bytes .../main/webapp/content/images/hipster2x.png | Bin 0 -> 18872 bytes .../webapp/content/images/logo-jhipster.png | Bin 0 -> 4459 bytes .../src/main/webapp/content/scss/global.scss | 211 ++++ .../src/main/webapp/content/scss/vendor.scss | 10 + jhipster/src/main/webapp/favicon.ico | Bin 0 -> 5430 bytes .../src/main/webapp/i18n/en/activate.json | 9 + jhipster/src/main/webapp/i18n/en/audits.json | 27 + jhipster/src/main/webapp/i18n/en/comment.json | 23 + .../main/webapp/i18n/en/configuration.json | 10 + jhipster/src/main/webapp/i18n/en/error.json | 6 + jhipster/src/main/webapp/i18n/en/gateway.json | 15 + jhipster/src/main/webapp/i18n/en/global.json | 133 +++ jhipster/src/main/webapp/i18n/en/health.json | 27 + jhipster/src/main/webapp/i18n/en/home.json | 19 + jhipster/src/main/webapp/i18n/en/login.json | 19 + jhipster/src/main/webapp/i18n/en/logs.json | 11 + jhipster/src/main/webapp/i18n/en/metrics.json | 101 ++ .../src/main/webapp/i18n/en/password.json | 12 + jhipster/src/main/webapp/i18n/en/post.json | 24 + .../src/main/webapp/i18n/en/register.json | 24 + jhipster/src/main/webapp/i18n/en/reset.json | 27 + .../src/main/webapp/i18n/en/sessions.json | 15 + .../src/main/webapp/i18n/en/settings.json | 32 + .../main/webapp/i18n/en/user-management.json | 30 + jhipster/src/main/webapp/index.html | 27 + jhipster/src/main/webapp/robots.txt | 11 + .../webapp/swagger-ui/images/throbber.gif | Bin 0 -> 9257 bytes .../src/main/webapp/swagger-ui/index.html | 177 +++ jhipster/src/test/gatling/conf/gatling.conf | 131 +++ jhipster/src/test/gatling/conf/logback.xml | 22 + .../simulations/CommentGatlingTest.scala | 92 ++ .../gatling/simulations/PostGatlingTest.scala | 92 ++ .../security/SecurityUtilsUnitTest.java | 50 + .../security/jwt/TokenProviderTest.java | 107 ++ .../baeldung/service/UserServiceIntTest.java | 129 ++ .../web/rest/AccountResourceIntTest.java | 395 +++++++ .../web/rest/AuditResourceIntTest.java | 147 +++ .../web/rest/CommentResourceIntTest.java | 279 +++++ .../web/rest/LogsResourceIntTest.java | 59 + .../web/rest/PostResourceIntTest.java | 306 +++++ .../web/rest/ProfileInfoResourceIntTest.java | 86 ++ .../java/com/baeldung/web/rest/TestUtil.java | 120 ++ .../web/rest/UserResourceIntTest.java | 522 +++++++++ .../javascript/e2e/account/account.spec.ts | 108 ++ .../e2e/admin/administration.spec.ts | 80 ++ .../javascript/e2e/entities/comment.spec.ts | 49 + .../test/javascript/e2e/entities/post.spec.ts | 49 + jhipster/src/test/javascript/karma.conf.js | 126 ++ .../src/test/javascript/protractor.conf.js | 48 + .../activate/activate.component.spec.ts | 84 ++ .../password-reset-finish.component.spec.ts | 79 ++ .../password-reset-init.component.spec.ts | 115 ++ .../password-strength-bar.component.spec.ts | 53 + .../password/password.component.spec.ts | 92 ++ .../register/register.component.spec.ts | 138 +++ .../settings/settings.component.spec.ts | 103 ++ .../app/admin/audits/audits.component.spec.ts | 82 ++ .../app/admin/health/health.component.spec.ts | 295 +++++ .../comment/comment-detail.component.spec.ts | 79 ++ .../post/post-detail.component.spec.ts | 79 ++ jhipster/src/test/javascript/spec/entry.ts | 19 + .../spec/helpers/mock-account.service.ts | 26 + .../spec/helpers/mock-language.service.ts | 26 + .../spec/helpers/mock-principal.service.ts | 20 + .../spec/helpers/mock-route.service.ts | 15 + .../test/javascript/spec/helpers/spyobject.ts | 69 ++ .../src/test/javascript/spec/test.module.ts | 24 + .../src/test/resources/config/application.yml | 96 ++ jhipster/src/test/resources/logback-test.xml | 15 + jhipster/tsconfig.json | 22 + jhipster/tslint.json | 107 ++ jhipster/webpack/webpack.common.js | 117 ++ jhipster/webpack/webpack.dev.js | 65 ++ jhipster/webpack/webpack.prod.js | 22 + jhipster/webpack/webpack.vendor.js | 63 + .../ArgumentMatcherWithoutLambdaUnitTest.java | 20 +- .../CustomAnswerWithoutLambdaUnitTest.java | 25 +- pom.xml | 1 + 361 files changed, 20698 insertions(+), 21 deletions(-) create mode 100644 jhipster/.editorconfig create mode 100644 jhipster/.gitattributes create mode 100644 jhipster/.gitignore create mode 100644 jhipster/.gitlab-ci.yml create mode 100644 jhipster/.jhipster/Comment.json create mode 100644 jhipster/.jhipster/Post.json create mode 100644 jhipster/.mvn/wrapper/maven-wrapper.jar create mode 100644 jhipster/.mvn/wrapper/maven-wrapper.properties create mode 100644 jhipster/.travis.yml create mode 100644 jhipster/.yo-rc.json create mode 100644 jhipster/Jenkinsfile create mode 100644 jhipster/README.md create mode 100644 jhipster/angular-cli.json create mode 100644 jhipster/circle.yml create mode 100755 jhipster/mvnw create mode 100644 jhipster/mvnw.cmd create mode 100644 jhipster/package.json create mode 100644 jhipster/pom.xml create mode 100644 jhipster/postcss.config.js create mode 100644 jhipster/src/main/docker/Dockerfile create mode 100644 jhipster/src/main/docker/app.yml create mode 100644 jhipster/src/main/docker/mysql.yml create mode 100644 jhipster/src/main/docker/sonar.yml create mode 100644 jhipster/src/main/java/com/baeldung/ApplicationWebXml.java create mode 100644 jhipster/src/main/java/com/baeldung/BaeldungApp.java create mode 100644 jhipster/src/main/java/com/baeldung/aop/logging/LoggingAspect.java create mode 100644 jhipster/src/main/java/com/baeldung/config/ApplicationProperties.java create mode 100644 jhipster/src/main/java/com/baeldung/config/AsyncConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/CacheConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/CloudDatabaseConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/Constants.java create mode 100644 jhipster/src/main/java/com/baeldung/config/DatabaseConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/DateTimeFormatConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/DefaultProfileUtil.java create mode 100644 jhipster/src/main/java/com/baeldung/config/LocaleConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/LoggingAspectConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/LoggingConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/MetricsConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/SecurityConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/ThymeleafConfiguration.java create mode 100644 jhipster/src/main/java/com/baeldung/config/WebConfigurer.java create mode 100644 jhipster/src/main/java/com/baeldung/config/audit/AuditEventConverter.java create mode 100644 jhipster/src/main/java/com/baeldung/config/audit/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/config/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/AbstractAuditingEntity.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/Authority.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/Comment.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/PersistentAuditEvent.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/Post.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/User.java create mode 100644 jhipster/src/main/java/com/baeldung/domain/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/AuthorityRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/CommentRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/CustomAuditEventRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/PersistenceAuditEventRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/PostRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/UserRepository.java create mode 100644 jhipster/src/main/java/com/baeldung/repository/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/security/AuthoritiesConstants.java create mode 100644 jhipster/src/main/java/com/baeldung/security/DomainUserDetailsService.java create mode 100644 jhipster/src/main/java/com/baeldung/security/SecurityUtils.java create mode 100644 jhipster/src/main/java/com/baeldung/security/SpringSecurityAuditorAware.java create mode 100644 jhipster/src/main/java/com/baeldung/security/UserNotActivatedException.java create mode 100644 jhipster/src/main/java/com/baeldung/security/jwt/JWTConfigurer.java create mode 100644 jhipster/src/main/java/com/baeldung/security/jwt/JWTFilter.java create mode 100644 jhipster/src/main/java/com/baeldung/security/jwt/TokenProvider.java create mode 100644 jhipster/src/main/java/com/baeldung/security/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/service/AuditEventService.java create mode 100644 jhipster/src/main/java/com/baeldung/service/MailService.java create mode 100644 jhipster/src/main/java/com/baeldung/service/UserService.java create mode 100644 jhipster/src/main/java/com/baeldung/service/dto/UserDTO.java create mode 100644 jhipster/src/main/java/com/baeldung/service/dto/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/service/mapper/UserMapper.java create mode 100644 jhipster/src/main/java/com/baeldung/service/mapper/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/service/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/service/util/RandomUtil.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/AccountResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/AuditResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/CommentResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/JWTToken.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/LogsResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/PostResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/ProfileInfoResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/UserJWTController.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/UserResource.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/CustomParameterizedException.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorConstants.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/ExceptionTranslator.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/FieldErrorVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/errors/ParameterizedErrorVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/package-info.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/util/HeaderUtil.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/util/PaginationUtil.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/vm/KeyAndPasswordVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/vm/LoggerVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/vm/LoginVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/vm/ManagedUserVM.java create mode 100644 jhipster/src/main/java/com/baeldung/web/rest/vm/package-info.java create mode 100644 jhipster/src/main/resources/.h2.server.properties create mode 100644 jhipster/src/main/resources/banner.txt create mode 100644 jhipster/src/main/resources/config/application-dev.yml create mode 100644 jhipster/src/main/resources/config/application-prod.yml create mode 100644 jhipster/src/main/resources/config/application.yml create mode 100644 jhipster/src/main/resources/config/liquibase/authorities.csv create mode 100644 jhipster/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml create mode 100644 jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_Post.xml create mode 100644 jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_constraints_Post.xml create mode 100644 jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_Comment.xml create mode 100644 jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_constraints_Comment.xml create mode 100644 jhipster/src/main/resources/config/liquibase/master.xml create mode 100644 jhipster/src/main/resources/config/liquibase/users.csv create mode 100644 jhipster/src/main/resources/config/liquibase/users_authorities.csv create mode 100644 jhipster/src/main/resources/i18n/messages.properties create mode 100644 jhipster/src/main/resources/i18n/messages_en.properties create mode 100644 jhipster/src/main/resources/logback-spring.xml create mode 100644 jhipster/src/main/resources/mails/activationEmail.html create mode 100644 jhipster/src/main/resources/mails/creationEmail.html create mode 100644 jhipster/src/main/resources/mails/passwordResetEmail.html create mode 100644 jhipster/src/main/resources/templates/error.html create mode 100644 jhipster/src/main/webapp/404.html create mode 100644 jhipster/src/main/webapp/app/account/account.module.ts create mode 100644 jhipster/src/main/webapp/app/account/account.route.ts create mode 100644 jhipster/src/main/webapp/app/account/activate/activate.component.html create mode 100644 jhipster/src/main/webapp/app/account/activate/activate.component.ts create mode 100644 jhipster/src/main/webapp/app/account/activate/activate.route.ts create mode 100644 jhipster/src/main/webapp/app/account/activate/activate.service.ts create mode 100644 jhipster/src/main/webapp/app/account/index.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html create mode 100644 jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html create mode 100644 jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts create mode 100644 jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts create mode 100644 jhipster/src/main/webapp/app/account/password/password-strength-bar.component.ts create mode 100644 jhipster/src/main/webapp/app/account/password/password-strength-bar.scss create mode 100644 jhipster/src/main/webapp/app/account/password/password.component.html create mode 100644 jhipster/src/main/webapp/app/account/password/password.component.ts create mode 100644 jhipster/src/main/webapp/app/account/password/password.route.ts create mode 100644 jhipster/src/main/webapp/app/account/password/password.service.ts create mode 100644 jhipster/src/main/webapp/app/account/register/register.component.html create mode 100644 jhipster/src/main/webapp/app/account/register/register.component.ts create mode 100644 jhipster/src/main/webapp/app/account/register/register.route.ts create mode 100644 jhipster/src/main/webapp/app/account/register/register.service.ts create mode 100644 jhipster/src/main/webapp/app/account/settings/settings.component.html create mode 100644 jhipster/src/main/webapp/app/account/settings/settings.component.ts create mode 100644 jhipster/src/main/webapp/app/account/settings/settings.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/admin.module.ts create mode 100644 jhipster/src/main/webapp/app/admin/admin.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/audits/audit-data.model.ts create mode 100644 jhipster/src/main/webapp/app/admin/audits/audit.model.ts create mode 100644 jhipster/src/main/webapp/app/admin/audits/audits.component.html create mode 100644 jhipster/src/main/webapp/app/admin/audits/audits.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/audits/audits.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/audits/audits.service.ts create mode 100644 jhipster/src/main/webapp/app/admin/configuration/configuration.component.html create mode 100644 jhipster/src/main/webapp/app/admin/configuration/configuration.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/configuration/configuration.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/configuration/configuration.service.ts create mode 100644 jhipster/src/main/webapp/app/admin/docs/docs.component.html create mode 100644 jhipster/src/main/webapp/app/admin/docs/docs.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/docs/docs.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/health/health-modal.component.html create mode 100644 jhipster/src/main/webapp/app/admin/health/health-modal.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/health/health.component.html create mode 100644 jhipster/src/main/webapp/app/admin/health/health.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/health/health.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/health/health.service.ts create mode 100644 jhipster/src/main/webapp/app/admin/index.ts create mode 100644 jhipster/src/main/webapp/app/admin/logs/log.model.ts create mode 100644 jhipster/src/main/webapp/app/admin/logs/logs.component.html create mode 100644 jhipster/src/main/webapp/app/admin/logs/logs.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/logs/logs.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/logs/logs.service.ts create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.html create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics.component.html create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/metrics/metrics.service.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.html create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management.component.html create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management.component.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-management.route.ts create mode 100644 jhipster/src/main/webapp/app/admin/user-management/user-modal.service.ts create mode 100644 jhipster/src/main/webapp/app/app.constants.ts create mode 100644 jhipster/src/main/webapp/app/app.main.ts create mode 100644 jhipster/src/main/webapp/app/app.module.ts create mode 100644 jhipster/src/main/webapp/app/app.route.ts create mode 100644 jhipster/src/main/webapp/app/blocks/config/prod.config.ts create mode 100644 jhipster/src/main/webapp/app/blocks/config/uib-pagination.config.ts create mode 100644 jhipster/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts create mode 100644 jhipster/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts create mode 100644 jhipster/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts create mode 100644 jhipster/src/main/webapp/app/blocks/interceptor/http.provider.ts create mode 100644 jhipster/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-detail.component.html create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-detail.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment-popup.service.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.component.html create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.model.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.module.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.route.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/comment.service.ts create mode 100644 jhipster/src/main/webapp/app/entities/comment/index.ts create mode 100644 jhipster/src/main/webapp/app/entities/entity.module.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/index.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post-detail.component.html create mode 100644 jhipster/src/main/webapp/app/entities/post/post-detail.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post-dialog.component.html create mode 100644 jhipster/src/main/webapp/app/entities/post/post-dialog.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post-popup.service.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post.component.html create mode 100644 jhipster/src/main/webapp/app/entities/post/post.component.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post.model.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post.module.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post.route.ts create mode 100644 jhipster/src/main/webapp/app/entities/post/post.service.ts create mode 100644 jhipster/src/main/webapp/app/home/home.component.html create mode 100644 jhipster/src/main/webapp/app/home/home.component.ts create mode 100644 jhipster/src/main/webapp/app/home/home.module.ts create mode 100644 jhipster/src/main/webapp/app/home/home.route.ts create mode 100644 jhipster/src/main/webapp/app/home/home.scss create mode 100644 jhipster/src/main/webapp/app/home/index.ts create mode 100644 jhipster/src/main/webapp/app/layouts/error/error.component.html create mode 100644 jhipster/src/main/webapp/app/layouts/error/error.component.ts create mode 100644 jhipster/src/main/webapp/app/layouts/error/error.route.ts create mode 100644 jhipster/src/main/webapp/app/layouts/footer/footer.component.html create mode 100644 jhipster/src/main/webapp/app/layouts/footer/footer.component.ts create mode 100644 jhipster/src/main/webapp/app/layouts/index.ts create mode 100644 jhipster/src/main/webapp/app/layouts/layout-routing.module.ts create mode 100644 jhipster/src/main/webapp/app/layouts/main/main.component.html create mode 100644 jhipster/src/main/webapp/app/layouts/main/main.component.ts create mode 100644 jhipster/src/main/webapp/app/layouts/navbar/active-menu.directive.ts create mode 100644 jhipster/src/main/webapp/app/layouts/navbar/navbar.component.html create mode 100644 jhipster/src/main/webapp/app/layouts/navbar/navbar.component.ts create mode 100644 jhipster/src/main/webapp/app/layouts/navbar/navbar.scss create mode 100644 jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts create mode 100644 jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.scss create mode 100644 jhipster/src/main/webapp/app/layouts/profiles/profile-info.model.ts create mode 100644 jhipster/src/main/webapp/app/layouts/profiles/profile.service.ts create mode 100644 jhipster/src/main/webapp/app/polyfills.ts create mode 100644 jhipster/src/main/webapp/app/shared/alert/alert-error.component.ts create mode 100644 jhipster/src/main/webapp/app/shared/alert/alert.component.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/account.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/auth-jwt.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/auth.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/csrf.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/has-any-authority.directive.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/principal.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/state-storage.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/auth/user-route-access-service.ts create mode 100644 jhipster/src/main/webapp/app/shared/constants/pagination.constants.ts create mode 100644 jhipster/src/main/webapp/app/shared/index.ts create mode 100644 jhipster/src/main/webapp/app/shared/language/language.constants.ts create mode 100644 jhipster/src/main/webapp/app/shared/language/language.helper.ts create mode 100644 jhipster/src/main/webapp/app/shared/language/language.pipe.ts create mode 100644 jhipster/src/main/webapp/app/shared/login/login-modal.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/login/login.component.html create mode 100644 jhipster/src/main/webapp/app/shared/login/login.component.ts create mode 100644 jhipster/src/main/webapp/app/shared/login/login.service.ts create mode 100644 jhipster/src/main/webapp/app/shared/shared-common.module.ts create mode 100644 jhipster/src/main/webapp/app/shared/shared-libs.module.ts create mode 100644 jhipster/src/main/webapp/app/shared/shared.module.ts create mode 100644 jhipster/src/main/webapp/app/shared/user/account.model.ts create mode 100644 jhipster/src/main/webapp/app/shared/user/user.model.ts create mode 100644 jhipster/src/main/webapp/app/shared/user/user.service.ts create mode 100644 jhipster/src/main/webapp/app/vendor.ts create mode 100644 jhipster/src/main/webapp/content/images/hipster.png create mode 100644 jhipster/src/main/webapp/content/images/hipster2x.png create mode 100644 jhipster/src/main/webapp/content/images/logo-jhipster.png create mode 100644 jhipster/src/main/webapp/content/scss/global.scss create mode 100644 jhipster/src/main/webapp/content/scss/vendor.scss create mode 100644 jhipster/src/main/webapp/favicon.ico create mode 100644 jhipster/src/main/webapp/i18n/en/activate.json create mode 100644 jhipster/src/main/webapp/i18n/en/audits.json create mode 100644 jhipster/src/main/webapp/i18n/en/comment.json create mode 100644 jhipster/src/main/webapp/i18n/en/configuration.json create mode 100644 jhipster/src/main/webapp/i18n/en/error.json create mode 100644 jhipster/src/main/webapp/i18n/en/gateway.json create mode 100644 jhipster/src/main/webapp/i18n/en/global.json create mode 100644 jhipster/src/main/webapp/i18n/en/health.json create mode 100644 jhipster/src/main/webapp/i18n/en/home.json create mode 100644 jhipster/src/main/webapp/i18n/en/login.json create mode 100644 jhipster/src/main/webapp/i18n/en/logs.json create mode 100644 jhipster/src/main/webapp/i18n/en/metrics.json create mode 100644 jhipster/src/main/webapp/i18n/en/password.json create mode 100644 jhipster/src/main/webapp/i18n/en/post.json create mode 100644 jhipster/src/main/webapp/i18n/en/register.json create mode 100644 jhipster/src/main/webapp/i18n/en/reset.json create mode 100644 jhipster/src/main/webapp/i18n/en/sessions.json create mode 100644 jhipster/src/main/webapp/i18n/en/settings.json create mode 100644 jhipster/src/main/webapp/i18n/en/user-management.json create mode 100644 jhipster/src/main/webapp/index.html create mode 100644 jhipster/src/main/webapp/robots.txt create mode 100644 jhipster/src/main/webapp/swagger-ui/images/throbber.gif create mode 100644 jhipster/src/main/webapp/swagger-ui/index.html create mode 100644 jhipster/src/test/gatling/conf/gatling.conf create mode 100644 jhipster/src/test/gatling/conf/logback.xml create mode 100644 jhipster/src/test/gatling/simulations/CommentGatlingTest.scala create mode 100644 jhipster/src/test/gatling/simulations/PostGatlingTest.scala create mode 100644 jhipster/src/test/java/com/baeldung/security/SecurityUtilsUnitTest.java create mode 100644 jhipster/src/test/java/com/baeldung/security/jwt/TokenProviderTest.java create mode 100644 jhipster/src/test/java/com/baeldung/service/UserServiceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/AccountResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/AuditResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/CommentResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/LogsResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/PostResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/ProfileInfoResourceIntTest.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/TestUtil.java create mode 100644 jhipster/src/test/java/com/baeldung/web/rest/UserResourceIntTest.java create mode 100644 jhipster/src/test/javascript/e2e/account/account.spec.ts create mode 100644 jhipster/src/test/javascript/e2e/admin/administration.spec.ts create mode 100644 jhipster/src/test/javascript/e2e/entities/comment.spec.ts create mode 100644 jhipster/src/test/javascript/e2e/entities/post.spec.ts create mode 100644 jhipster/src/test/javascript/karma.conf.js create mode 100644 jhipster/src/test/javascript/protractor.conf.js create mode 100644 jhipster/src/test/javascript/spec/app/account/activate/activate.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/password/password.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/register/register.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/account/settings/settings.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/admin/health/health.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/entities/comment/comment-detail.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/app/entities/post/post-detail.component.spec.ts create mode 100644 jhipster/src/test/javascript/spec/entry.ts create mode 100644 jhipster/src/test/javascript/spec/helpers/mock-account.service.ts create mode 100644 jhipster/src/test/javascript/spec/helpers/mock-language.service.ts create mode 100644 jhipster/src/test/javascript/spec/helpers/mock-principal.service.ts create mode 100644 jhipster/src/test/javascript/spec/helpers/mock-route.service.ts create mode 100644 jhipster/src/test/javascript/spec/helpers/spyobject.ts create mode 100644 jhipster/src/test/javascript/spec/test.module.ts create mode 100644 jhipster/src/test/resources/config/application.yml create mode 100644 jhipster/src/test/resources/logback-test.xml create mode 100644 jhipster/tsconfig.json create mode 100644 jhipster/tslint.json create mode 100644 jhipster/webpack/webpack.common.js create mode 100644 jhipster/webpack/webpack.dev.js create mode 100644 jhipster/webpack/webpack.prod.js create mode 100644 jhipster/webpack/webpack.vendor.js diff --git a/jhipster/.editorconfig b/jhipster/.editorconfig new file mode 100644 index 0000000000..a03599dd04 --- /dev/null +++ b/jhipster/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 4 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[{package,bower}.json] +indent_style = space +indent_size = 2 diff --git a/jhipster/.gitattributes b/jhipster/.gitattributes new file mode 100644 index 0000000000..2a13efa88f --- /dev/null +++ b/jhipster/.gitattributes @@ -0,0 +1,22 @@ +# All text files should have the "lf" (Unix) line endings +* text eol=lf + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.java text +*.js text +*.css text +*.html text + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.jar binary +*.pdf binary +*.eot binary +*.ttf binary +*.gzip binary +*.gz binary +*.ai binary +*.eps binary +*.swf binary diff --git a/jhipster/.gitignore b/jhipster/.gitignore new file mode 100644 index 0000000000..c9f735a496 --- /dev/null +++ b/jhipster/.gitignore @@ -0,0 +1,143 @@ +###################### +# Project Specific +###################### +/src/main/webapp/content/css/main.css +/target/www/** +/src/test/javascript/coverage/ +/src/test/javascript/PhantomJS*/ + +###################### +# Node +###################### +/node/ +node_tmp/ +node_modules/ +npm-debug.log.* + +###################### +# SASS +###################### +.sass-cache/ + +###################### +# Eclipse +###################### +*.pydevproject +.project +.metadata +tmp/ +tmp/**/* +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath +.factorypath +/src/main/resources/rebel.xml + +# External tool builders +.externalToolBuilders/** + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + +###################### +# Intellij +###################### +.idea/ +*.iml +*.iws +*.ipr +*.ids +*.orig + +###################### +# Visual Studio Code +###################### +.vscode/ + +###################### +# Maven +###################### +/log/ +/target/ + +###################### +# Gradle +###################### +.gradle/ +/build/ + +###################### +# Package Files +###################### +*.jar +*.war +*.ear +*.db + +###################### +# Windows +###################### +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + +###################### +# Mac OSX +###################### +.DS_Store +.svn + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +###################### +# Directories +###################### +/bin/ +/deploy/ + +###################### +# Logs +###################### +*.log + +###################### +# Others +###################### +*.class +*.*~ +*~ +.merge_file* + +###################### +# Gradle Wrapper +###################### +!gradle/wrapper/gradle-wrapper.jar + +###################### +# Maven Wrapper +###################### +!.mvn/wrapper/maven-wrapper.jar + +###################### +# ESLint +###################### +.eslintcache +/.apt_generated/ diff --git a/jhipster/.gitlab-ci.yml b/jhipster/.gitlab-ci.yml new file mode 100644 index 0000000000..1cf574251a --- /dev/null +++ b/jhipster/.gitlab-ci.yml @@ -0,0 +1,56 @@ + +cache: + key: "$CI_BUILD_REF_NAME" + paths: + - node_modules + - .maven +stages: + - build + - test + - package + +before_script: + - export MAVEN_USER_HOME=`pwd`/.maven + - chmod +x mvnw + - ./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0 + - ./mvnw com.github.eirslett:frontend-maven-plugin:npm + +maven-build: + stage: build + script: ./mvnw compile -Dmaven.repo.local=$MAVEN_USER_HOME + +maven-test: + stage: test + script: + - ./mvnw test -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/surefire-reports/* +maven-front-test: + stage: test + script: + - ./mvnw com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.yarn.arguments=test + artifacts: + paths: + - target/test-results/karma/* +gatling-test: + stage: test + allow_failure: true + script: + - ./mvnw gatling:execute -Dmaven.repo.local=$MAVEN_USER_HOME + before_script: + - export MAVEN_USER_HOME=`pwd`/.maven + - chmod +x mvnw + - ./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0 + - ./mvnw com.github.eirslett:frontend-maven-plugin:npm + - ./mvnw & + artifacts: + paths: + - target/gatling/* +maven-package: + stage: package + script: + - ./mvnw package -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME + artifacts: + paths: + - target/*.war diff --git a/jhipster/.jhipster/Comment.json b/jhipster/.jhipster/Comment.json new file mode 100644 index 0000000000..c6022daa60 --- /dev/null +++ b/jhipster/.jhipster/Comment.json @@ -0,0 +1,39 @@ +{ + "fluentMethods": true, + "relationships": [ + { + "relationshipName": "post", + "otherEntityName": "post", + "relationshipType": "many-to-one", + "relationshipValidateRules": [ + "required" + ], + "otherEntityField": "title" + } + ], + "fields": [ + { + "fieldName": "text", + "fieldType": "String", + "fieldValidateRules": [ + "required", + "minlength", + "maxlength" + ], + "fieldValidateRulesMinlength": "10", + "fieldValidateRulesMaxlength": "100" + }, + { + "fieldName": "creationDate", + "fieldType": "LocalDate", + "fieldValidateRules": [ + "required" + ] + } + ], + "changelogDate": "20170316224021", + "dto": "no", + "service": "no", + "entityTableName": "comment", + "pagination": "infinite-scroll" +} diff --git a/jhipster/.jhipster/Post.json b/jhipster/.jhipster/Post.json new file mode 100644 index 0000000000..595cf43598 --- /dev/null +++ b/jhipster/.jhipster/Post.json @@ -0,0 +1,52 @@ +{ + "fluentMethods": true, + "relationships": [ + { + "relationshipName": "creator", + "otherEntityName": "user", + "relationshipType": "many-to-one", + "relationshipValidateRules": [ + "required" + ], + "otherEntityField": "login", + "ownerSide": true, + "otherEntityRelationshipName": "post" + } + ], + "fields": [ + { + "fieldName": "title", + "fieldType": "String", + "fieldValidateRules": [ + "required", + "minlength", + "maxlength" + ], + "fieldValidateRulesMinlength": "10", + "fieldValidateRulesMaxlength": "100" + }, + { + "fieldName": "content", + "fieldType": "String", + "fieldValidateRules": [ + "required", + "minlength", + "maxlength" + ], + "fieldValidateRulesMinlength": "10", + "fieldValidateRulesMaxlength": "1000" + }, + { + "fieldName": "creationDate", + "fieldType": "LocalDate", + "fieldValidateRules": [ + "required" + ] + } + ], + "changelogDate": "20170316223211", + "dto": "no", + "service": "no", + "entityTableName": "post", + "pagination": "infinite-scroll" +} diff --git a/jhipster/.mvn/wrapper/maven-wrapper.jar b/jhipster/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..5fd4d5023f1463b5ba3970e33c460c1eb26d748d GIT binary patch literal 49502 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%0A$pwhjXzyA0ZzErH{1@M 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 OJOEd-=rxTO#Qy`$*1Hh^ literal 0 HcmV?d00001 diff --git a/jhipster/.mvn/wrapper/maven-wrapper.properties b/jhipster/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..c954cec91c --- /dev/null +++ b/jhipster/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip diff --git a/jhipster/.travis.yml b/jhipster/.travis.yml new file mode 100644 index 0000000000..c34d1a7da6 --- /dev/null +++ b/jhipster/.travis.yml @@ -0,0 +1,41 @@ +os: + - linux +services: + - docker +language: node_js +node_js: + - "6.10.0" +jdk: + - oraclejdk8 +sudo: false +cache: + directories: + - node + - node_modules + - $HOME/.m2 +env: + global: + - NODE_VERSION=6.10.0 + - SPRING_OUTPUT_ANSI_ENABLED=ALWAYS + - SPRING_JPA_SHOW_SQL=false +before_install: + - jdk_switcher use oraclejdk8 + - java -version + - sudo /etc/init.d/mysql stop + - sudo /etc/init.d/postgresql stop + - nvm install $NODE_VERSION + - npm install -g npm + - node -v + - npm -v +install: + - npm install +script: + - chmod +x mvnw + - ./mvnw clean test + - npm test + - ./mvnw package -Pprod -DskipTests +notifications: + webhooks: + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/jhipster/.yo-rc.json b/jhipster/.yo-rc.json new file mode 100644 index 0000000000..155e33b1c5 --- /dev/null +++ b/jhipster/.yo-rc.json @@ -0,0 +1,36 @@ +{ + "generator-jhipster": { + "jhipsterVersion": "4.0.8", + "baseName": "baeldung", + "packageName": "com.baeldung", + "packageFolder": "com/baeldung", + "serverPort": "8080", + "authenticationType": "jwt", + "hibernateCache": "ehcache", + "clusteredHttpSession": false, + "websocket": false, + "databaseType": "sql", + "devDatabaseType": "h2Disk", + "prodDatabaseType": "mysql", + "searchEngine": false, + "messageBroker": false, + "serviceDiscoveryType": false, + "buildTool": "maven", + "enableSocialSignIn": false, + "jwtSecretKey": "e1d4b69d3f953e3fa622121e882e6f459ca20ca4", + "clientFramework": "angular2", + "useSass": true, + "clientPackageManager": "npm", + "applicationType": "monolith", + "testFrameworks": [ + "gatling", + "protractor" + ], + "jhiPrefix": "jhi", + "enableTranslation": true, + "nativeLanguage": "en", + "languages": [ + "en" + ] + } +} \ No newline at end of file diff --git a/jhipster/Jenkinsfile b/jhipster/Jenkinsfile new file mode 100644 index 0000000000..1f0873a472 --- /dev/null +++ b/jhipster/Jenkinsfile @@ -0,0 +1,50 @@ +#!/usr/bin/env groovy + +node { + stage('checkout') { + checkout scm + } + + stage('check java') { + sh "java -version" + } + + stage('clean') { + sh "chmod +x mvnw" + sh "./mvnw clean" + } + + stage('install tools') { + sh "./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0" + } + + stage('npm install') { + sh "./mvnw com.github.eirslett:frontend-maven-plugin:npm" + } + + stage('backend tests') { + try { + sh "./mvnw test" + } catch(err) { + throw err + } finally { + junit '**/target/surefire-reports/TEST-*.xml' + } + } + + stage('frontend tests') { + try { + sh "./mvnw com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.yarn.arguments=test" + } catch(err) { + throw err + } finally { + junit '**/target/test-results/karma/TESTS-*.xml' + } + } + + stage('packaging') { + sh "./mvnw package -Pprod -DskipTests" + archiveArtifacts artifacts: '**/target/*.war', fingerprint: true + } + +} diff --git a/jhipster/README.md b/jhipster/README.md new file mode 100644 index 0000000000..d45796d867 --- /dev/null +++ b/jhipster/README.md @@ -0,0 +1,153 @@ +# baeldung +This application was generated using JHipster 4.0.8, you can find documentation and help at [https://jhipster.github.io/documentation-archive/v4.0.8](https://jhipster.github.io/documentation-archive/v4.0.8). + +## Development + +Before you can build this project, you must install and configure the following dependencies on your machine: + +1. [Node.js][]: We use Node to run a development web server and build the project. + Depending on your system, you can install Node either from source or as a pre-packaged bundle. + +After installing Node, you should be able to run the following command to install development tools. +You will only need to run this command when dependencies change in [package.json](package.json). + + npm install + +We use npm scripts and [Webpack][] as our build system. + + +Run the following commands in two separate terminals to create a blissful development experience where your browser +auto-refreshes when files change on your hard drive. + + ./mvnw + npm start + +[Npm][] is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by +specifying a newer version in [package.json](package.json). You can also run `npm update` and `npm install` to manage dependencies. +Add the `help` flag on any command to see how you can use it. For example, `npm help update`. + +The `npm run` command will list all of the scripts available to run for this project. + +### Managing dependencies + +For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command: + + npm install --save --save-exact leaflet + +To benefit from TypeScript type definitions from [DefinitelyTyped][] repository in development, you would run following command: + + npm install --save-dev --save-exact @types/leaflet + +Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them: + +Edit [src/main/webapp/app/vendor.ts](src/main/webapp/app/vendor.ts) file: +~~~ +import 'leaflet/dist/leaflet.js'; +~~~ + +Edit [src/main/webapp/content/css/vendor.css](src/main/webapp/content/css/vendor.css) file: +~~~ +@import '~leaflet/dist/leaflet.css'; +~~~ + +Note: there are still few other things remaining to do for Leaflet that we won't detail here. + +For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. + +### Using angular-cli + +You can also use [Angular CLI][] to generate some custom client code. + +For example, the following command: + + ng generate component my-component + +will generate few files: + + create src/main/webapp/app/my-component/my-component.component.html + create src/main/webapp/app/my-component/my-component.component.ts + update src/main/webapp/app/app.module.ts + +## Building for production + +To optimize the baeldung application for production, run: + + ./mvnw -Pprod clean package + +This will concatenate and minify the client CSS and JavaScript files. It will also modify `index.html` so it references these new files. +To ensure everything worked, run: + + java -jar target/*.war + +Then navigate to [http://localhost:8080](http://localhost:8080) in your browser. + +Refer to [Using JHipster in production][] for more details. + +## Testing + +To launch your application's tests, run: + + ./mvnw clean test + +### Client tests + +Unit tests are run by [Karma][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with: + + npm test + +UI end-to-end tests are powered by [Protractor][], which is built on top of WebDriverJS. They're located in [src/test/javascript/e2e](src/test/javascript/e2e) +and can be run by starting Spring Boot in one terminal (`./mvnw spring-boot:run`) and running the tests (`gulp itest`) in a second one. +### Other tests + +Performance tests are run by [Gatling][] and written in Scala. They're located in [src/test/gatling](src/test/gatling) and can be run with: + + ./mvnw gatling:execute + +For more information, refer to the [Running tests page][]. + +## Using Docker to simplify development (optional) + +You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. +For example, to start a mysql database in a docker container, run: + + docker-compose -f src/main/docker/mysql.yml up -d + +To stop it and remove the container, run: + + docker-compose -f src/main/docker/mysql.yml down + +You can also fully dockerize your application and all the services that it depends on. +To achieve this, first build a docker image of your app by running: + + ./mvnw package -Pprod docker:build + +Then run: + + docker-compose -f src/main/docker/app.yml up -d + +For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`yo jhipster:docker-compose`), which is able to generate docker configurations for one or several JHipster applications. + +## Continuous Integration (optional) + +To configure CI for your project, run the ci-cd sub-generator (`yo jhipster:ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information. + +[JHipster Homepage and latest documentation]: https://jhipster.github.io +[JHipster 4.0.8 archive]: https://jhipster.github.io/documentation-archive/v4.0.8 + +[Using JHipster in development]: https://jhipster.github.io/documentation-archive/v4.0.8/development/ +[Using Docker and Docker-Compose]: https://jhipster.github.io/documentation-archive/v4.0.8/docker-compose +[Using JHipster in production]: https://jhipster.github.io/documentation-archive/v4.0.8/production/ +[Running tests page]: https://jhipster.github.io/documentation-archive/v4.0.8/running-tests/ +[Setting up Continuous Integration]: https://jhipster.github.io/documentation-archive/v4.0.8/setting-up-ci/ + +[Gatling]: http://gatling.io/ +[Node.js]: https://nodejs.org/ +[Yarn]: https://yarnpkg.org/ +[Webpack]: https://webpack.github.io/ +[Angular CLI]: https://cli.angular.io/ +[BrowserSync]: http://www.browsersync.io/ +[Karma]: http://karma-runner.github.io/ +[Jasmine]: http://jasmine.github.io/2.0/introduction.html +[Protractor]: https://angular.github.io/protractor/ +[Leaflet]: http://leafletjs.com/ +[DefinitelyTyped]: http://definitelytyped.org/ diff --git a/jhipster/angular-cli.json b/jhipster/angular-cli.json new file mode 100644 index 0000000000..15558a2fae --- /dev/null +++ b/jhipster/angular-cli.json @@ -0,0 +1,55 @@ +{ + "project": { + "version": "1.0.0-beta.24", + "name": "baeldung" + }, + "apps": [ + { + "root": "src/main/webapp/", + "outDir": "target/www/app", + "assets": [ + "content", + "favicon.ico" + ], + "index": "index.html", + "main": "app/app.main.ts", + "test": "", + "tsconfig": "../../../tsconfig.json", + "prefix": "jhi", + "mobile": false, + "styles": [ + "content/css/main.css" + ], + "scripts": [], + "environments": {} + } + ], + "addons": [], + "packages": [], + "e2e": { + "protractor": { + "config": "src/test/javascript/protractor.conf.js" + } + }, + "test": { + "karma": { + "config": "src/test/javascript/karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "prefixInterfaces": false, + "inline": { + "style": true, + "template": false + }, + "spec": { + "class": false, + "component": false, + "directive": false, + "module": false, + "pipe": false, + "service": false + } + } +} diff --git a/jhipster/circle.yml b/jhipster/circle.yml new file mode 100644 index 0000000000..bc9371e94f --- /dev/null +++ b/jhipster/circle.yml @@ -0,0 +1,25 @@ +machine: + services: + - docker + java: + version: oraclejdk8 + node: + version: 6.10.0 +dependencies: + cache_directories: + - node + - node_modules + - ~/.m2 + override: + - java -version + - npm install -g npm + - node -v + - npm -v + - java -version + - npm install +test: + override: + - chmod +x mvnw + - ./mvnw clean test + - npm test + - ./mvnw package -Pprod -DskipTests diff --git a/jhipster/mvnw b/jhipster/mvnw new file mode 100755 index 0000000000..a1ba1bf554 --- /dev/null +++ b/jhipster/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/jhipster/mvnw.cmd b/jhipster/mvnw.cmd new file mode 100644 index 0000000000..2b934e89dd --- /dev/null +++ b/jhipster/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/jhipster/package.json b/jhipster/package.json new file mode 100644 index 0000000000..40bbd28799 --- /dev/null +++ b/jhipster/package.json @@ -0,0 +1,112 @@ +{ + "name": "baeldung", + "version": "0.0.0", + "description": "Description for baeldung", + "private": true, + "cacheDirectories": [ + "node_modules" + ], + "dependencies": { + "@angular/common": "2.4.7", + "@angular/compiler": "2.4.7", + "@angular/core": "2.4.7", + "@angular/forms": "2.4.7", + "@angular/http": "2.4.7", + "@angular/platform-browser": "2.4.7", + "@angular/platform-browser-dynamic": "2.4.7", + "@angular/router": "3.4.7", + "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.20", + "angular2-infinite-scroll": "0.3.0", + "bootstrap": "4.0.0-alpha.6", + "font-awesome": "4.7.0", + "angular2-cookie": "1.2.6", + "core-js": "2.4.1", + "jquery": "3.1.1", + "ng-jhipster": "0.1.9", + "ng2-webstorage": "1.5.0", + "reflect-metadata": "0.1.9", + "rxjs": "5.1.0", + "swagger-ui": "2.2.10", + "tether": "1.4.0", + "zone.js": "0.7.6" + }, + "devDependencies": { + "@angular/cli": "1.0.0-beta.28.3", + "@types/jasmine": "2.5.42", + "@types/node": "7.0.5", + "@types/selenium-webdriver": "2.53.39", + "add-asset-html-webpack-plugin": "1.0.2", + "angular2-template-loader": "0.6.2", + "awesome-typescript-loader": "3.0.7", + "browser-sync": "2.18.7", + "browser-sync-webpack-plugin": "1.1.4", + "codelyzer": "2.0.0", + "copy-webpack-plugin": "4.0.1", + "css-loader": "0.26.1", + "del": "2.2.2", + "event-stream": "3.3.4", + "exports-loader": "0.6.3", + "extract-text-webpack-plugin": "2.0.0-beta.5", + "file-loader": "0.10.0", + "generator-jhipster": "4.0.8", + "html-webpack-plugin": "2.28.0", + "image-webpack-loader": "3.2.0", + "jasmine-core": "2.5.2", + "jasmine-reporters": "2.2.0", + "karma": "1.4.1", + "karma-chrome-launcher": "2.0.0", + "karma-coverage": "1.1.1", + "karma-intl-shim": "1.0.3", + "karma-jasmine": "1.1.0", + "karma-junit-reporter": "1.2.0", + "karma-phantomjs-launcher": "1.0.2", + "karma-remap-istanbul": "0.6.0", + "karma-sourcemap-loader": "0.3.7", + "karma-webpack": "2.0.2", + "lazypipe": "1.0.1", + "lodash": "4.17.4", + "map-stream": "0.0.6", + "phantomjs-prebuilt": "2.1.14", + "protractor": "5.1.1", + "protractor-jasmine2-screenshot-reporter": "0.3.3", + "ts-node": "2.1.0", + "proxy-middleware": "0.15.0", + "raw-loader": "0.5.1", + "run-sequence": "1.2.2", + "sourcemap-istanbul-instrumenter-loader": "0.2.0", + "string-replace-webpack-plugin": "0.0.5", + "style-loader": "0.13.1", + "to-string-loader": "1.1.5", + "tslint": "4.4.2", + "tslint-loader": "3.4.1", + "typescript": "2.1.6", + "webpack": "2.2.1", + "webpack-dev-server": "2.3.0", + "webpack-merge": "2.6.1", + "webpack-visualizer-plugin": "0.1.10", + "write-file-webpack-plugin": "3.4.2", + "xml2js": "0.4.17", + "sass-loader": "5.0.1", + "node-sass": "4.5.0", + "postcss-loader": "1.3.0", + "yargs": "6.6.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "scripts": { + "lint": "tslint 'src/main/webapp/app/**/*.ts' --force", + "lint:fix": "tslint 'src/main/webapp/app/**/*.ts' --fix --force", + "tsc": "tsc", + "tsc:w": "tsc -w", + "start": "npm run webpack:dev", + "webpack:build": "webpack --config webpack/webpack.vendor.js && webpack --config webpack/webpack.dev.js", + "webpack:build:dev": "webpack --config webpack/webpack.dev.js", + "webpack:dev": "webpack-dev-server --config webpack/webpack.dev.js --progress --inline --hot --profile --port=9060", + "webpack:prod": "npm test && webpack -p --config webpack/webpack.vendor.js && webpack -p --config webpack/webpack.prod.js", + "test": "npm run lint && karma start src/test/javascript/karma.conf.js", + "test:watch": "karma start --watch", + "e2e": "protractor src/test/javascript/protractor.conf.js", + "postinstall": "webdriver-manager update && npm run webpack:build" + } +} diff --git a/jhipster/pom.xml b/jhipster/pom.xml new file mode 100644 index 0000000000..ba78ad4e2b --- /dev/null +++ b/jhipster/pom.xml @@ -0,0 +1,1034 @@ + + + 4.0.0 + + + spring-boot-starter-parent + org.springframework.boot + 1.5.2.RELEASE + + + + com.baeldung + jhipster-monolithic + 0.0.1-SNAPSHOT + war + JHipster Monolithic Application + + + ${maven.version} + + + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + + + com.fasterxml.jackson.datatype + jackson-datatype-hppc + + + com.fasterxml.jackson.datatype + jackson-datatype-json-org + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.h2database + h2 + + + com.jayway.jsonpath + json-path + test + + + + com.jcraft + jzlib + ${jzlib.version} + + + com.mattbertolini + liquibase-slf4j + ${liquibase-slf4j.version} + + + com.ryantenney.metrics + metrics-spring + ${metrics-spring.version} + + + metrics-annotation + com.codahale.metrics + + + metrics-core + com.codahale.metrics + + + metrics-healthchecks + com.codahale.metrics + + + + + com.zaxxer + HikariCP + + + tools + com.sun + + + + + + commons-io + commons-io + ${commons-io.version} + + + io.dropwizard.metrics + metrics-annotation + ${dropwizard-metrics.version} + + + io.dropwizard.metrics + metrics-core + + + io.dropwizard.metrics + metrics-json + ${dropwizard-metrics.version} + + + io.dropwizard.metrics + metrics-jvm + ${dropwizard-metrics.version} + + + io.dropwizard.metrics + metrics-servlet + ${dropwizard-metrics.version} + + + io.dropwizard.metrics + metrics-servlets + + + io.gatling.highcharts + gatling-charts-highcharts + ${gatling.version} + test + + + io.github.jhipster + jhipster + ${jhipster.server.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + io.springfox + springfox-bean-validators + ${springfox.version} + + + io.springfox + springfox-swagger2 + ${springfox.version} + + + mapstruct + org.mapstruct + + + + + javax.cache + cache-api + + + mysql + mysql-connector-java + + + + net.logstash.logback + logstash-logback-encoder + ${logstash-logback-encoder.version} + + + logback-core + ch.qos.logback + + + logback-classic + ch.qos.logback + + + logback-access + ch.qos.logback + + + + + org.apache.commons + commons-lang3 + ${commons-lang.version} + + + org.assertj + assertj-core + test + + + org.awaitility + awaitility + ${awaitility.version} + test + + + org.ehcache + ehcache + + + org.hibernate + hibernate-envers + + + org.hibernate + hibernate-jcache + ${hibernate.version} + + + org.hibernate + hibernate-validator + + + org.liquibase + liquibase-core + + + jetty-servlet + org.eclipse.jetty + + + + + org.mapstruct + mapstruct-jdk8 + ${mapstruct.version} + + + org.springframework + spring-context-support + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-loader-tools + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-cloud-connectors + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-tomcat + org.springframework.boot + + + + + org.springframework.boot + spring-boot-test + test + + + + org.springframework.security + spring-security-data + + + org.springframework.security + spring-security-test + test + + + + + spring-boot:run + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + prepare-agent + + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + install-node-and-npm + npm + + + + + + + + + + + + + + + com.github.ekryd.sortpom + sortpom-maven-plugin + ${sortpom-maven-plugin.version} + + + verify + + sort + + + + + true + 4 + groupId,artifactId + groupId,artifactId + true + false + + + + com.spotify + docker-maven-plugin + ${docker-maven-plugin.version} + + baeldung + src/main/docker + + + / + ${project.build.directory} + ${project.build.finalName}.war + + + + + + io.gatling + gatling-maven-plugin + ${gatling-maven-plugin.version} + + src/test/gatling/conf + src/test/gatling/data + target/gatling/results + src/test/gatling/bodies + src/test/gatling/simulations + + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + true + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-versions + + enforce + + + + + + + You are running an older version of + Maven. JHipster requires at least Maven + ${maven.version} + [${maven.version},) + + + You are running an older version of + Java. JHipster requires at least JDK + ${java.version} + [${java.version}.0,) + + + + + + org.apache.maven.plugins + maven-resources-plugin + ${maven-resources-plugin.version} + + + default-resources + validate + + copy-resources + + + target/classes + false + + # + + + + src/main/resources/ + true + + **/*.xml + **/*.yml + + + + src/main/resources/ + false + + **/*.xml + **/*.yml + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + alphabetical + + **/*IntTest.java + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-tests + + prepare-agent + + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + + + + + post-unit-test + test + + report + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + ${project.testresult.directory}/coverage/jacoco + + + + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + + javax.validation + validation-api + ${validation-api.version} + + + org.javassist + javassist + ${javassist.version} + + + org.liquibase.ext + liquibase-hibernate5 + ${liquibase-hibernate5.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${project.parent.version} + + + + src/main/resources/config/liquibase/master.xml + src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + org.h2.Driver + jdbc:h2:file:./target/h2db/db/baeldung + + baeldung + + hibernate:spring:com.baeldung.domain?dialect=org.hibernate.dialect.H2Dialect&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + true + debug + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar-maven-plugin.version} + + + org.springframework.boot + spring-boot-maven-plugin + + true + true + + + + + + + + + no-liquibase + + ,no-liquibase + + + + swagger + + ,swagger + + + + webpack + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + webpack build dev + generate-resources + + npm + + + run webpack:build:dev + + + + + + + + + dev + + true + + + + + org.apache.maven.plugins + maven-war-plugin + + src/main/webapp/ + + + + + + + DEBUG + + dev${profile.no-liquibase} + + + + org.springframework.boot + spring-boot-devtools + true + + + org.springframework.boot + spring-boot-starter-undertow + + + + + prod + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + install node and npm + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + npm install + + npm + + + install + + + + npm rebuild node-sass + + npm + + + rebuild node-sass + + + + webpack build prod + generate-resources + + npm + + + run webpack:prod + + + + + + maven-clean-plugin + + + + target/www/ + + + + + + org.apache.maven.plugins + maven-war-plugin + + target/www/ + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + true + + + + + + + INFO + + prod${profile.swagger}${profile.no-liquibase} + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + cc + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + compile + compile + + add-source + compile + + + + test-compile + test-compile + + add-source + testCompile + + + + + incremental + true + ${scala.version} + + + + org.apache.maven.plugins + maven-compiler-plugin + + + default-compile + none + + + default-testCompile + none + + + + + org.apache.maven.plugins + maven-war-plugin + + src/main/webapp/ + + + + org.springframework.boot + spring-boot-maven-plugin + + true + true + true + + + + + + + + DEBUG + + dev,swagger + + + + org.springframework.boot + spring-boot-devtools + true + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + graphite + + + io.dropwizard.metrics + metrics-graphite + + + + + + prometheus + + + io.prometheus + simpleclient + ${prometheus-simpleclient.version} + + + io.prometheus + simpleclient_dropwizard + ${prometheus-simpleclient.version} + + + io.prometheus + simpleclient_servlet + ${prometheus-simpleclient.version} + + + + + + IDE + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + integration + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*IntTest.java + + + + + + + + + + + + -Djava.security.egd=file:/dev/./urandom -Xmx256m + 3.6.2 + 2.0.0 + 2.5 + 3.5 + 0.4.13 + 1.3 + 2.2.1 + 2.2.3 + 5.2.8.Final + 2.6.0 + 0.7.9 + 1.8 + 3.21.0-GA + 1.0.0 + 1.1.0 + 0.7.0 + 1.1.3 + 3.6 + 2.0.0 + 4.8 + jdt_apt + 1.1.0.Final + 3.6.0 + 1.4.1 + 3.0.1 + yyyyMMddHHmmss + ${java.version} + ${java.version} + 3.0.0 + 3.1.3 + v6.10.0 + 4.3.0 + + + + + ${project.build.directory}/test-results + 0.0.20 + false + 3.2.2 + 2.12.1 + 3.2 + + src/main/webapp/content/**/*.*, + src/main/webapp/bower_components/**/*.*, + src/main/webapp/i18n/*.js, target/www/**/*.* + + S3437,UndocumentedApi,BoldAndItalicTagsCheck + + + src/main/webapp/app/**/*.* + Web:BoldAndItalicTagsCheck + + src/main/java/**/* + squid:S3437 + + src/main/java/**/* + squid:UndocumentedApi + + ${project.testresult.directory}/coverage/jacoco/jacoco-it.exec + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + jacoco + + ${project.testresult.directory}/karma + + ${project.testresult.directory}/coverage/report-lcov/lcov.info + + ${project.testresult.directory}/coverage/report-lcov/lcov.info + + ${project.basedir}/src/main/ + ${project.testresult.directory}/surefire-reports + ${project.basedir}/src/test/ + + 2.5.0 + + 2.6.1 + 1.4.10.Final + 1.1.0.Final + + diff --git a/jhipster/postcss.config.js b/jhipster/postcss.config.js new file mode 100644 index 0000000000..f549c034d5 --- /dev/null +++ b/jhipster/postcss.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: [] +} diff --git a/jhipster/src/main/docker/Dockerfile b/jhipster/src/main/docker/Dockerfile new file mode 100644 index 0000000000..66991b2998 --- /dev/null +++ b/jhipster/src/main/docker/Dockerfile @@ -0,0 +1,13 @@ +FROM openjdk:8-jre-alpine + +ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ + JHIPSTER_SLEEP=0 + +# add directly the war +ADD *.war /app.war + +VOLUME /tmp +EXPOSE 8080 +CMD echo "The application will start in ${JHIPSTER_SLEEP}s..." && \ + sleep ${JHIPSTER_SLEEP} && \ + java -Djava.security.egd=file:/dev/./urandom -jar /app.war diff --git a/jhipster/src/main/docker/app.yml b/jhipster/src/main/docker/app.yml new file mode 100644 index 0000000000..78cd2c1602 --- /dev/null +++ b/jhipster/src/main/docker/app.yml @@ -0,0 +1,14 @@ +version: '2' +services: + baeldung-app: + image: baeldung + environment: + - SPRING_PROFILES_ACTIVE=prod,swagger + - SPRING_DATASOURCE_URL=jdbc:mysql://baeldung-mysql:3306/baeldung?useUnicode=true&characterEncoding=utf8&useSSL=false + - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application + ports: + - 8080:8080 + baeldung-mysql: + extends: + file: mysql.yml + service: baeldung-mysql diff --git a/jhipster/src/main/docker/mysql.yml b/jhipster/src/main/docker/mysql.yml new file mode 100644 index 0000000000..5038d09504 --- /dev/null +++ b/jhipster/src/main/docker/mysql.yml @@ -0,0 +1,13 @@ +version: '2' +services: + baeldung-mysql: + image: mysql:5.7.13 + # volumes: + # - ~/volumes/jhipster/baeldung/mysql/:/var/lib/mysql/ + environment: + - MYSQL_USER=root + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + - MYSQL_DATABASE=baeldung + ports: + - 3306:3306 + command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8 diff --git a/jhipster/src/main/docker/sonar.yml b/jhipster/src/main/docker/sonar.yml new file mode 100644 index 0000000000..718be83b4d --- /dev/null +++ b/jhipster/src/main/docker/sonar.yml @@ -0,0 +1,7 @@ +version: '2' +services: + baeldung-sonar: + image: sonarqube:6.2-alpine + ports: + - 9000:9000 + - 9092:9092 diff --git a/jhipster/src/main/java/com/baeldung/ApplicationWebXml.java b/jhipster/src/main/java/com/baeldung/ApplicationWebXml.java new file mode 100644 index 0000000000..762d18420c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/ApplicationWebXml.java @@ -0,0 +1,21 @@ +package com.baeldung; + +import com.baeldung.config.DefaultProfileUtil; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; + +/** + * This is a helper Java class that provides an alternative to creating a web.xml. + * This will be invoked only when the application is deployed to a servlet container like Tomcat, JBoss etc. + */ +public class ApplicationWebXml extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + /** + * set a default to use when no profile is configured. + */ + DefaultProfileUtil.addDefaultProfile(application.application()); + return application.sources(BaeldungApp.class); + } +} diff --git a/jhipster/src/main/java/com/baeldung/BaeldungApp.java b/jhipster/src/main/java/com/baeldung/BaeldungApp.java new file mode 100644 index 0000000000..13b6b2b3fa --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/BaeldungApp.java @@ -0,0 +1,84 @@ +package com.baeldung; + +import com.baeldung.config.ApplicationProperties; +import com.baeldung.config.DefaultProfileUtil; + +import io.github.jhipster.config.JHipsterConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.*; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.env.Environment; + +import javax.annotation.PostConstruct; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collection; + +@ComponentScan +@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class}) +@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class}) +public class BaeldungApp { + + private static final Logger log = LoggerFactory.getLogger(BaeldungApp.class); + + private final Environment env; + + public BaeldungApp(Environment env) { + this.env = env; + } + + /** + * Initializes baeldung. + *

+ * Spring profiles can be configured with a program arguments --spring.profiles.active=your-active-profile + *

+ * You can find more information on how profiles work with JHipster on http://jhipster.github.io/profiles/. + */ + @PostConstruct + public void initApplication() { + Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + log.error("You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time."); + } + if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) { + log.error("You have misconfigured your application! It should not" + + "run with both the 'dev' and 'cloud' profiles at the same time."); + } + } + + /** + * Main method, used to run the application. + * + * @param args the command line arguments + * @throws UnknownHostException if the local host name could not be resolved into an address + */ + public static void main(String[] args) throws UnknownHostException { + SpringApplication app = new SpringApplication(BaeldungApp.class); + DefaultProfileUtil.addDefaultProfile(app); + Environment env = app.run(args).getEnvironment(); + String protocol = "http"; + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https"; + } + log.info("\n----------------------------------------------------------\n\t" + + "Application '{}' is running! Access URLs:\n\t" + + "Local: \t\t{}://localhost:{}\n\t" + + "External: \t{}://{}:{}\n\t" + + "Profile(s): \t{}\n----------------------------------------------------------", + env.getProperty("spring.application.name"), + protocol, + env.getProperty("server.port"), + protocol, + InetAddress.getLocalHost().getHostAddress(), + env.getProperty("server.port"), + env.getActiveProfiles()); + } +} diff --git a/jhipster/src/main/java/com/baeldung/aop/logging/LoggingAspect.java b/jhipster/src/main/java/com/baeldung/aop/logging/LoggingAspect.java new file mode 100644 index 0000000000..7fbd352820 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/aop/logging/LoggingAspect.java @@ -0,0 +1,79 @@ +package com.baeldung.aop.logging; + +import io.github.jhipster.config.JHipsterConstants; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; + +import java.util.Arrays; + +/** + * Aspect for logging execution of service and repository Spring components. + * + * By default, it only runs with the "dev" profile. + */ +@Aspect +public class LoggingAspect { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private final Environment env; + + public LoggingAspect(Environment env) { + this.env = env; + } + + /** + * Pointcut that matches all repositories, services and Web REST endpoints. + */ + @Pointcut("within(com.baeldung.repository..*) || within(com.baeldung.service..*) || within(com.baeldung.web.rest..*)") + public void loggingPointcut() { + // Method is empty as this is just a Pointcut, the implementations are in the advices. + } + + /** + * Advice that logs methods throwing exceptions. + */ + @AfterThrowing(pointcut = "loggingPointcut()", throwing = "e") + public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e); + + } else { + log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL"); + } + } + + /** + * Advice that logs when a method is entered and exited. + */ + @Around("loggingPointcut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + if (log.isDebugEnabled()) { + log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); + } + try { + Object result = joinPoint.proceed(); + if (log.isDebugEnabled()) { + log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName(), result); + } + return result; + } catch (IllegalArgumentException e) { + log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()), + joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + + throw e; + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/ApplicationProperties.java b/jhipster/src/main/java/com/baeldung/config/ApplicationProperties.java new file mode 100644 index 0000000000..add1782678 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/ApplicationProperties.java @@ -0,0 +1,15 @@ +package com.baeldung.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties specific to JHipster. + * + *

+ * Properties are configured in the application.yml file. + *

+ */ +@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) +public class ApplicationProperties { + +} diff --git a/jhipster/src/main/java/com/baeldung/config/AsyncConfiguration.java b/jhipster/src/main/java/com/baeldung/config/AsyncConfiguration.java new file mode 100644 index 0000000000..dc1ba37514 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/AsyncConfiguration.java @@ -0,0 +1,46 @@ +package com.baeldung.config; + +import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor; +import io.github.jhipster.config.JHipsterProperties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.*; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@Configuration +@EnableAsync +@EnableScheduling +public class AsyncConfiguration implements AsyncConfigurer { + + private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); + + private final JHipsterProperties jHipsterProperties; + + public AsyncConfiguration(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @Override + @Bean(name = "taskExecutor") + public Executor getAsyncExecutor() { + log.debug("Creating Async Task Executor"); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); + executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); + executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); + executor.setThreadNamePrefix("baeldung-Executor-"); + return new ExceptionHandlingAsyncTaskExecutor(executor); + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new SimpleAsyncUncaughtExceptionHandler(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/CacheConfiguration.java b/jhipster/src/main/java/com/baeldung/config/CacheConfiguration.java new file mode 100644 index 0000000000..4323fa076a --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/CacheConfiguration.java @@ -0,0 +1,48 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterProperties; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; +import org.ehcache.expiry.Duration; +import org.ehcache.expiry.Expirations; +import org.ehcache.jsr107.Eh107Configuration; + +import java.util.concurrent.TimeUnit; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.*; + +@Configuration +@EnableCaching +@AutoConfigureAfter(value = { MetricsConfiguration.class }) +@AutoConfigureBefore(value = { WebConfigurer.class, DatabaseConfiguration.class }) +public class CacheConfiguration { + + private final javax.cache.configuration.Configuration jcacheConfiguration; + + public CacheConfiguration(JHipsterProperties jHipsterProperties) { + JHipsterProperties.Cache.Ehcache ehcache = + jHipsterProperties.getCache().getEhcache(); + + jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration( + CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, + ResourcePoolsBuilder.heap(ehcache.getMaxEntries())) + .withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS))) + .build()); + } + + @Bean + public JCacheManagerCustomizer cacheManagerCustomizer() { + return cm -> { + cm.createCache(com.baeldung.domain.User.class.getName(), jcacheConfiguration); + cm.createCache(com.baeldung.domain.Authority.class.getName(), jcacheConfiguration); + cm.createCache(com.baeldung.domain.User.class.getName() + ".authorities", jcacheConfiguration); + cm.createCache(com.baeldung.domain.Post.class.getName(), jcacheConfiguration); + cm.createCache(com.baeldung.domain.Comment.class.getName(), jcacheConfiguration); + // jhipster-needle-ehcache-add-entry + }; + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/CloudDatabaseConfiguration.java b/jhipster/src/main/java/com/baeldung/config/CloudDatabaseConfiguration.java new file mode 100644 index 0000000000..cae9ec1e82 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/CloudDatabaseConfiguration.java @@ -0,0 +1,23 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.config.java.AbstractCloudConfig; +import org.springframework.context.annotation.*; + +import javax.sql.DataSource; + +@Configuration +@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD) +public class CloudDatabaseConfiguration extends AbstractCloudConfig { + + private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class); + + @Bean + public DataSource dataSource() { + log.info("Configuring JDBC datasource from a cloud provider"); + return connectionFactory().dataSource(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/Constants.java b/jhipster/src/main/java/com/baeldung/config/Constants.java new file mode 100644 index 0000000000..9d797c1934 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/Constants.java @@ -0,0 +1,16 @@ +package com.baeldung.config; + +/** + * Application constants. + */ +public final class Constants { + + //Regex for acceptable logins + public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$"; + + public static final String SYSTEM_ACCOUNT = "system"; + public static final String ANONYMOUS_USER = "anonymoususer"; + + private Constants() { + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/DatabaseConfiguration.java b/jhipster/src/main/java/com/baeldung/config/DatabaseConfiguration.java new file mode 100644 index 0000000000..b64fd7cc82 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/DatabaseConfiguration.java @@ -0,0 +1,75 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.liquibase.AsyncSpringLiquibase; + +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; +import liquibase.integration.spring.SpringLiquibase; +import org.h2.tools.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.core.task.TaskExecutor; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.sql.SQLException; + +@Configuration +@EnableJpaRepositories("com.baeldung.repository") +@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") +@EnableTransactionManagement +public class DatabaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); + + private final Environment env; + + public DatabaseConfiguration(Environment env) { + this.env = env; + } + + /** + * Open the TCP port for the H2 database, so it is available remotely. + * + * @return the H2 database TCP server + * @throws SQLException if the server failed to start + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public Server h2TCPServer() throws SQLException { + return Server.createTcpServer("-tcp","-tcpAllowOthers"); + } + + @Bean + public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor, + DataSource dataSource, LiquibaseProperties liquibaseProperties) { + + // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously + SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env); + liquibase.setDataSource(dataSource); + liquibase.setChangeLog("classpath:config/liquibase/master.xml"); + liquibase.setContexts(liquibaseProperties.getContexts()); + liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); + liquibase.setDropFirst(liquibaseProperties.isDropFirst()); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) { + liquibase.setShouldRun(false); + } else { + liquibase.setShouldRun(liquibaseProperties.isEnabled()); + log.debug("Configuring Liquibase"); + } + return liquibase; + } + + @Bean + public Hibernate5Module hibernate5Module() { + return new Hibernate5Module(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/DateTimeFormatConfiguration.java b/jhipster/src/main/java/com/baeldung/config/DateTimeFormatConfiguration.java new file mode 100644 index 0000000000..aab57adfb0 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/DateTimeFormatConfiguration.java @@ -0,0 +1,17 @@ +package com.baeldung.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +public class DateTimeFormatConfiguration extends WebMvcConfigurerAdapter { + + @Override + public void addFormatters(FormatterRegistry registry) { + DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); + registrar.setUseIsoFormat(true); + registrar.registerFormatters(registry); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/DefaultProfileUtil.java b/jhipster/src/main/java/com/baeldung/config/DefaultProfileUtil.java new file mode 100644 index 0000000000..7918fb49a4 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/DefaultProfileUtil.java @@ -0,0 +1,48 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.boot.SpringApplication; +import org.springframework.core.env.Environment; + +import java.util.*; + +/** + * Utility class to load a Spring profile to be used as default + * when there is no spring.profiles.active set in the environment or as command line argument. + * If the value is not available in application.yml then dev profile will be used as default. + */ +public final class DefaultProfileUtil { + + private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default"; + + private DefaultProfileUtil() { + } + + /** + * Set a default to use when no profile is configured. + * + * @param app the Spring application + */ + public static void addDefaultProfile(SpringApplication app) { + Map defProperties = new HashMap<>(); + /* + * The default profile to use when no other profiles are defined + * This cannot be set in the application.yml file. + * See https://github.com/spring-projects/spring-boot/issues/1219 + */ + defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT); + app.setDefaultProperties(defProperties); + } + + /** + * Get the profiles that are applied else get default profiles. + */ + public static String[] getActiveProfiles(Environment env) { + String[] profiles = env.getActiveProfiles(); + if (profiles.length == 0) { + return env.getDefaultProfiles(); + } + return profiles; + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/LocaleConfiguration.java b/jhipster/src/main/java/com/baeldung/config/LocaleConfiguration.java new file mode 100644 index 0000000000..dd3a499d56 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/LocaleConfiguration.java @@ -0,0 +1,35 @@ +package com.baeldung.config; + +import io.github.jhipster.config.locale.AngularCookieLocaleResolver; + +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +@Configuration +public class LocaleConfiguration extends WebMvcConfigurerAdapter implements EnvironmentAware { + + @Override + public void setEnvironment(Environment environment) { + // unused + } + + @Bean(name = "localeResolver") + public LocaleResolver localeResolver() { + AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); + cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); + return cookieLocaleResolver; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("language"); + registry.addInterceptor(localeChangeInterceptor); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/LoggingAspectConfiguration.java b/jhipster/src/main/java/com/baeldung/config/LoggingAspectConfiguration.java new file mode 100644 index 0000000000..936f54709a --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/LoggingAspectConfiguration.java @@ -0,0 +1,19 @@ +package com.baeldung.config; + +import com.baeldung.aop.logging.LoggingAspect; + +import io.github.jhipster.config.JHipsterConstants; + +import org.springframework.context.annotation.*; +import org.springframework.core.env.Environment; + +@Configuration +@EnableAspectJAutoProxy +public class LoggingAspectConfiguration { + + @Bean + @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) + public LoggingAspect loggingAspect(Environment env) { + return new LoggingAspect(env); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/LoggingConfiguration.java b/jhipster/src/main/java/com/baeldung/config/LoggingConfiguration.java new file mode 100644 index 0000000000..3ca6a48821 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/LoggingConfiguration.java @@ -0,0 +1,109 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterProperties; + +import ch.qos.logback.classic.AsyncAppender; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.LoggerContextListener; +import ch.qos.logback.core.spi.ContextAwareBase; +import net.logstash.logback.appender.LogstashSocketAppender; +import net.logstash.logback.stacktrace.ShortenedThrowableConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LoggingConfiguration { + + private final Logger log = LoggerFactory.getLogger(LoggingConfiguration.class); + + private LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + + @Value("${spring.application.name}") + private String appName; + + @Value("${server.port}") + private String serverPort; + + private final JHipsterProperties jHipsterProperties; + + public LoggingConfiguration(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + if (jHipsterProperties.getLogging().getLogstash().isEnabled()) { + addLogstashAppender(context); + + // Add context listener + LogbackLoggerContextListener loggerContextListener = new LogbackLoggerContextListener(); + loggerContextListener.setContext(context); + context.addListener(loggerContextListener); + } + } + + public void addLogstashAppender(LoggerContext context) { + log.info("Initializing Logstash logging"); + + LogstashSocketAppender logstashAppender = new LogstashSocketAppender(); + logstashAppender.setName("LOGSTASH"); + logstashAppender.setContext(context); + String customFields = "{\"app_name\":\"" + appName + "\",\"app_port\":\"" + serverPort + "\"}"; + + // Set the Logstash appender config from JHipster properties + logstashAppender.setSyslogHost(jHipsterProperties.getLogging().getLogstash().getHost()); + logstashAppender.setPort(jHipsterProperties.getLogging().getLogstash().getPort()); + logstashAppender.setCustomFields(customFields); + + // Limit the maximum length of the forwarded stacktrace so that it won't exceed the 8KB UDP limit of logstash + ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter(); + throwableConverter.setMaxLength(7500); + throwableConverter.setRootCauseFirst(true); + logstashAppender.setThrowableConverter(throwableConverter); + + logstashAppender.start(); + + // Wrap the appender in an Async appender for performance + AsyncAppender asyncLogstashAppender = new AsyncAppender(); + asyncLogstashAppender.setContext(context); + asyncLogstashAppender.setName("ASYNC_LOGSTASH"); + asyncLogstashAppender.setQueueSize(jHipsterProperties.getLogging().getLogstash().getQueueSize()); + asyncLogstashAppender.addAppender(logstashAppender); + asyncLogstashAppender.start(); + + context.getLogger("ROOT").addAppender(asyncLogstashAppender); + } + + /** + * Logback configuration is achieved by configuration file and API. + * When configuration file change is detected, the configuration is reset. + * This listener ensures that the programmatic configuration is also re-applied after reset. + */ + class LogbackLoggerContextListener extends ContextAwareBase implements LoggerContextListener { + + @Override + public boolean isResetResistant() { + return true; + } + + @Override + public void onStart(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onReset(LoggerContext context) { + addLogstashAppender(context); + } + + @Override + public void onStop(LoggerContext context) { + // Nothing to do. + } + + @Override + public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) { + // Nothing to do. + } + } + +} diff --git a/jhipster/src/main/java/com/baeldung/config/MetricsConfiguration.java b/jhipster/src/main/java/com/baeldung/config/MetricsConfiguration.java new file mode 100644 index 0000000000..94a50bed91 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/MetricsConfiguration.java @@ -0,0 +1,94 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.config.jcache.JCacheGaugeSet; + +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Slf4jReporter; +import com.codahale.metrics.health.HealthCheckRegistry; +import com.codahale.metrics.jvm.*; +import com.ryantenney.metrics.spring.config.annotation.EnableMetrics; +import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter; +import com.zaxxer.hikari.HikariDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.*; + +import javax.annotation.PostConstruct; +import java.lang.management.ManagementFactory; +import java.util.concurrent.TimeUnit; + +@Configuration +@EnableMetrics(proxyTargetClass = true) +public class MetricsConfiguration extends MetricsConfigurerAdapter { + + private static final String PROP_METRIC_REG_JVM_MEMORY = "jvm.memory"; + private static final String PROP_METRIC_REG_JVM_GARBAGE = "jvm.garbage"; + private static final String PROP_METRIC_REG_JVM_THREADS = "jvm.threads"; + private static final String PROP_METRIC_REG_JVM_FILES = "jvm.files"; + private static final String PROP_METRIC_REG_JVM_BUFFERS = "jvm.buffers"; + + private static final String PROP_METRIC_REG_JCACHE_STATISTICS = "jcache.statistics"; + private final Logger log = LoggerFactory.getLogger(MetricsConfiguration.class); + + private MetricRegistry metricRegistry = new MetricRegistry(); + + private HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry(); + + private final JHipsterProperties jHipsterProperties; + + private HikariDataSource hikariDataSource; + + public MetricsConfiguration(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @Autowired(required = false) + public void setHikariDataSource(HikariDataSource hikariDataSource) { + this.hikariDataSource = hikariDataSource; + } + + @Override + @Bean + public MetricRegistry getMetricRegistry() { + return metricRegistry; + } + + @Override + @Bean + public HealthCheckRegistry getHealthCheckRegistry() { + return healthCheckRegistry; + } + + @PostConstruct + public void init() { + log.debug("Registering JVM gauges"); + metricRegistry.register(PROP_METRIC_REG_JVM_MEMORY, new MemoryUsageGaugeSet()); + metricRegistry.register(PROP_METRIC_REG_JVM_GARBAGE, new GarbageCollectorMetricSet()); + metricRegistry.register(PROP_METRIC_REG_JVM_THREADS, new ThreadStatesGaugeSet()); + metricRegistry.register(PROP_METRIC_REG_JVM_FILES, new FileDescriptorRatioGauge()); + metricRegistry.register(PROP_METRIC_REG_JVM_BUFFERS, new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer())); + + metricRegistry.register(PROP_METRIC_REG_JCACHE_STATISTICS, new JCacheGaugeSet()); + if (hikariDataSource != null) { + log.debug("Monitoring the datasource"); + hikariDataSource.setMetricRegistry(metricRegistry); + } + if (jHipsterProperties.getMetrics().getJmx().isEnabled()) { + log.debug("Initializing Metrics JMX reporting"); + JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).build(); + jmxReporter.start(); + } + if (jHipsterProperties.getMetrics().getLogs().isEnabled()) { + log.info("Initializing Metrics Log reporting"); + final Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry) + .outputTo(LoggerFactory.getLogger("metrics")) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.start(jHipsterProperties.getMetrics().getLogs().getReportFrequency(), TimeUnit.SECONDS); + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/SecurityConfiguration.java b/jhipster/src/main/java/com/baeldung/config/SecurityConfiguration.java new file mode 100644 index 0000000000..118d302fcf --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/SecurityConfiguration.java @@ -0,0 +1,127 @@ +package com.baeldung.config; + +import com.baeldung.security.*; +import com.baeldung.security.jwt.*; + +import io.github.jhipster.security.*; + +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.CorsFilter; + +import javax.annotation.PostConstruct; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + private final UserDetailsService userDetailsService; + + private final TokenProvider tokenProvider; + + private final CorsFilter corsFilter; + + public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, + TokenProvider tokenProvider, + CorsFilter corsFilter) { + + this.authenticationManagerBuilder = authenticationManagerBuilder; + this.userDetailsService = userDetailsService; + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + } + + @PostConstruct + public void init() { + try { + authenticationManagerBuilder + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder()); + } catch (Exception e) { + throw new BeanInitializationException("Security configuration failed", e); + } + } + + @Bean + public Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint() { + return new Http401UnauthorizedEntryPoint(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring() + .antMatchers(HttpMethod.OPTIONS, "/**") + .antMatchers("/app/**/*.{js,html}") + .antMatchers("/bower_components/**") + .antMatchers("/i18n/**") + .antMatchers("/content/**") + .antMatchers("/swagger-ui/index.html") + .antMatchers("/test/**") + .antMatchers("/h2-console/**"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling() + .authenticationEntryPoint(http401UnauthorizedEntryPoint()) + .and() + .csrf() + .disable() + .headers() + .frameOptions() + .disable() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/api/register").permitAll() + .antMatchers("/api/activate").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/account/reset_password/init").permitAll() + .antMatchers("/api/account/reset_password/finish").permitAll() + .antMatchers("/api/profile-info").permitAll() + .antMatchers("/api/**").authenticated() + .antMatchers("/management/health").permitAll() + .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN) + .antMatchers("/v2/api-docs/**").permitAll() + .antMatchers("/swagger-resources/configuration/ui").permitAll() + .antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN) + .and() + .apply(securityConfigurerAdapter()); + + } + + private JWTConfigurer securityConfigurerAdapter() { + return new JWTConfigurer(tokenProvider); + } + + @Bean + public SecurityEvaluationContextExtension securityEvaluationContextExtension() { + return new SecurityEvaluationContextExtension(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/ThymeleafConfiguration.java b/jhipster/src/main/java/com/baeldung/config/ThymeleafConfiguration.java new file mode 100644 index 0000000000..68afcae71a --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/ThymeleafConfiguration.java @@ -0,0 +1,26 @@ +package com.baeldung.config; + +import org.apache.commons.lang3.CharEncoding; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.*; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; + +@Configuration +public class ThymeleafConfiguration { + + @SuppressWarnings("unused") + private final Logger log = LoggerFactory.getLogger(ThymeleafConfiguration.class); + + @Bean + @Description("Thymeleaf template resolver serving HTML 5 emails") + public ClassLoaderTemplateResolver emailTemplateResolver() { + ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver(); + emailTemplateResolver.setPrefix("mails/"); + emailTemplateResolver.setSuffix(".html"); + emailTemplateResolver.setTemplateMode("HTML5"); + emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8); + emailTemplateResolver.setOrder(1); + return emailTemplateResolver; + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/WebConfigurer.java b/jhipster/src/main/java/com/baeldung/config/WebConfigurer.java new file mode 100644 index 0000000000..bd80a063eb --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/WebConfigurer.java @@ -0,0 +1,186 @@ +package com.baeldung.config; + +import io.github.jhipster.config.JHipsterConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.github.jhipster.web.filter.CachingHttpHeadersFilter; + +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.servlet.InstrumentedFilter; +import com.codahale.metrics.servlets.MetricsServlet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.*; +import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; +import io.undertow.UndertowOptions; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.io.File; +import java.nio.file.Paths; +import java.util.*; +import javax.servlet.*; + +/** + * Configuration of web application with Servlet 3.0 APIs. + */ +@Configuration +public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer { + + private final Logger log = LoggerFactory.getLogger(WebConfigurer.class); + + private final Environment env; + + private final JHipsterProperties jHipsterProperties; + + private MetricRegistry metricRegistry; + + public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) { + + this.env = env; + this.jHipsterProperties = jHipsterProperties; + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + if (env.getActiveProfiles().length != 0) { + log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles()); + } + EnumSet disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC); + initMetrics(servletContext, disps); + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { + initCachingHttpHeadersFilter(servletContext, disps); + } + if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + initH2Console(servletContext); + } + log.info("Web application fully configured"); + } + + /** + * Customize the Servlet engine: Mime types, the document root, the cache. + */ + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 + mappings.add("html", "text/html;charset=utf-8"); + // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 + mappings.add("json", "text/html;charset=utf-8"); + container.setMimeMappings(mappings); + // When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets. + setLocationForStaticAssets(container); + + /* + * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288 + * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1. + * See the JHipsterProperties class and your application-*.yml configuration files + * for more information. + */ + if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) && + container instanceof UndertowEmbeddedServletContainerFactory) { + + ((UndertowEmbeddedServletContainerFactory) container) + .addBuilderCustomizers(builder -> + builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true)); + } + } + + private void setLocationForStaticAssets(ConfigurableEmbeddedServletContainer container) { + File root; + String prefixPath = resolvePathPrefix(); + root = new File(prefixPath + "target/www/"); + if (root.exists() && root.isDirectory()) { + container.setDocumentRoot(root); + } + } + + /** + * Resolve path prefix to static resources. + */ + private String resolvePathPrefix() { + String fullExecutablePath = this.getClass().getResource("").getPath(); + String rootPath = Paths.get(".").toUri().normalize().getPath(); + String extractedPath = fullExecutablePath.replace(rootPath, ""); + int extractionEndIndex = extractedPath.indexOf("target/"); + if(extractionEndIndex <= 0) { + return ""; + } + return extractedPath.substring(0, extractionEndIndex); + } + + /** + * Initializes the caching HTTP Headers Filter. + */ + private void initCachingHttpHeadersFilter(ServletContext servletContext, + EnumSet disps) { + log.debug("Registering Caching HTTP Headers Filter"); + FilterRegistration.Dynamic cachingHttpHeadersFilter = + servletContext.addFilter("cachingHttpHeadersFilter", + new CachingHttpHeadersFilter(jHipsterProperties)); + + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*"); + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*"); + cachingHttpHeadersFilter.setAsyncSupported(true); + } + + /** + * Initializes Metrics. + */ + private void initMetrics(ServletContext servletContext, EnumSet disps) { + log.debug("Initializing Metrics registries"); + servletContext.setAttribute(InstrumentedFilter.REGISTRY_ATTRIBUTE, + metricRegistry); + servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY, + metricRegistry); + + log.debug("Registering Metrics Filter"); + FilterRegistration.Dynamic metricsFilter = servletContext.addFilter("webappMetricsFilter", + new InstrumentedFilter()); + + metricsFilter.addMappingForUrlPatterns(disps, true, "/*"); + metricsFilter.setAsyncSupported(true); + + log.debug("Registering Metrics Servlet"); + ServletRegistration.Dynamic metricsAdminServlet = + servletContext.addServlet("metricsServlet", new MetricsServlet()); + + metricsAdminServlet.addMapping("/management/metrics/*"); + metricsAdminServlet.setAsyncSupported(true); + metricsAdminServlet.setLoadOnStartup(2); + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = jHipsterProperties.getCors(); + if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) { + log.debug("Registering CORS filter"); + source.registerCorsConfiguration("/api/**", config); + source.registerCorsConfiguration("/v2/api-docs", config); + } + return new CorsFilter(source); + } + + /** + * Initializes H2 console. + */ + private void initH2Console(ServletContext servletContext) { + log.debug("Initialize H2 console"); + ServletRegistration.Dynamic h2ConsoleServlet = servletContext.addServlet("H2Console", new org.h2.server.web.WebServlet()); + h2ConsoleServlet.addMapping("/h2-console/*"); + h2ConsoleServlet.setInitParameter("-properties", "src/main/resources/"); + h2ConsoleServlet.setLoadOnStartup(1); + } + + @Autowired(required = false) + public void setMetricRegistry(MetricRegistry metricRegistry) { + this.metricRegistry = metricRegistry; + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/audit/AuditEventConverter.java b/jhipster/src/main/java/com/baeldung/config/audit/AuditEventConverter.java new file mode 100644 index 0000000000..2062320751 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/audit/AuditEventConverter.java @@ -0,0 +1,91 @@ +package com.baeldung.config.audit; + +import com.baeldung.domain.PersistentAuditEvent; + +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.time.ZoneId; +import java.util.*; + +@Component +public class AuditEventConverter { + + /** + * Convert a list of PersistentAuditEvent to a list of AuditEvent + * + * @param persistentAuditEvents the list to convert + * @return the converted list. + */ + public List convertToAuditEvent(Iterable persistentAuditEvents) { + if (persistentAuditEvents == null) { + return Collections.emptyList(); + } + List auditEvents = new ArrayList<>(); + for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) { + auditEvents.add(convertToAuditEvent(persistentAuditEvent)); + } + return auditEvents; + } + + /** + * Convert a PersistentAuditEvent to an AuditEvent + * + * @param persistentAuditEvent the event to convert + * @return the converted list. + */ + public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) { + Instant instant = persistentAuditEvent.getAuditEventDate().atZone(ZoneId.systemDefault()).toInstant(); + return new AuditEvent(Date.from(instant), persistentAuditEvent.getPrincipal(), + persistentAuditEvent.getAuditEventType(), convertDataToObjects(persistentAuditEvent.getData())); + } + + /** + * Internal conversion. This is needed to support the current SpringBoot actuator AuditEventRepository interface + * + * @param data the data to convert + * @return a map of String, Object + */ + public Map convertDataToObjects(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + results.put(entry.getKey(), entry.getValue()); + } + } + return results; + } + + /** + * Internal conversion. This method will allow to save additional data. + * By default, it will save the object as string + * + * @param data the data to convert + * @return a map of String, String + */ + public Map convertDataToStrings(Map data) { + Map results = new HashMap<>(); + + if (data != null) { + for (Map.Entry entry : data.entrySet()) { + Object object = entry.getValue(); + + // Extract the data that will be saved. + if (object instanceof WebAuthenticationDetails) { + WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) object; + results.put("remoteAddress", authenticationDetails.getRemoteAddress()); + results.put("sessionId", authenticationDetails.getSessionId()); + } else if (object != null) { + results.put(entry.getKey(), object.toString()); + } else { + results.put(entry.getKey(), "null"); + } + } + } + + return results; + } +} diff --git a/jhipster/src/main/java/com/baeldung/config/audit/package-info.java b/jhipster/src/main/java/com/baeldung/config/audit/package-info.java new file mode 100644 index 0000000000..8ed4f851f0 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/audit/package-info.java @@ -0,0 +1,4 @@ +/** + * Audit specific code. + */ +package com.baeldung.config.audit; diff --git a/jhipster/src/main/java/com/baeldung/config/package-info.java b/jhipster/src/main/java/com/baeldung/config/package-info.java new file mode 100644 index 0000000000..5e54ad6d03 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/config/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Framework configuration files. + */ +package com.baeldung.config; diff --git a/jhipster/src/main/java/com/baeldung/domain/AbstractAuditingEntity.java b/jhipster/src/main/java/com/baeldung/domain/AbstractAuditingEntity.java new file mode 100644 index 0000000000..2d181e5dc8 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/AbstractAuditingEntity.java @@ -0,0 +1,80 @@ +package com.baeldung.domain; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.envers.Audited; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; + +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import java.time.ZonedDateTime; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; + +/** + * Base abstract class for entities which will hold definitions for created, last modified by and created, + * last modified by date. + */ +@MappedSuperclass +@Audited +@EntityListeners(AuditingEntityListener.class) +public abstract class AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @CreatedBy + @Column(name = "created_by", nullable = false, length = 50, updatable = false) + @JsonIgnore + private String createdBy; + + @CreatedDate + @Column(name = "created_date", nullable = false) + @JsonIgnore + private ZonedDateTime createdDate = ZonedDateTime.now(); + + @LastModifiedBy + @Column(name = "last_modified_by", length = 50) + @JsonIgnore + private String lastModifiedBy; + + @LastModifiedDate + @Column(name = "last_modified_date") + @JsonIgnore + private ZonedDateTime lastModifiedDate = ZonedDateTime.now(); + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public ZonedDateTime getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(ZonedDateTime createdDate) { + this.createdDate = createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public ZonedDateTime getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/Authority.java b/jhipster/src/main/java/com/baeldung/domain/Authority.java new file mode 100644 index 0000000000..8a94ad0bb2 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/Authority.java @@ -0,0 +1,66 @@ +package com.baeldung.domain; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Column; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * An authority (a security role) used by Spring Security. + */ +@Entity +@Table(name = "jhi_authority") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class Authority implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Size(min = 0, max = 50) + @Id + @Column(length = 50) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Authority authority = (Authority) o; + + if (name != null ? !name.equals(authority.name) : authority.name != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 0; + } + + @Override + public String toString() { + return "Authority{" + + "name='" + name + '\'' + + "}"; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/Comment.java b/jhipster/src/main/java/com/baeldung/domain/Comment.java new file mode 100644 index 0000000000..c4587b6231 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/Comment.java @@ -0,0 +1,114 @@ +package com.baeldung.domain; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; + +/** + * A Comment. + */ +@Entity +@Table(name = "comment") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class Comment implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Size(min = 10, max = 100) + @Column(name = "text", length = 100, nullable = false) + private String text; + + @NotNull + @Column(name = "creation_date", nullable = false) + private LocalDate creationDate; + + @ManyToOne(optional = false) + @NotNull + private Post post; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getText() { + return text; + } + + public Comment text(String text) { + this.text = text; + return this; + } + + public void setText(String text) { + this.text = text; + } + + public LocalDate getCreationDate() { + return creationDate; + } + + public Comment creationDate(LocalDate creationDate) { + this.creationDate = creationDate; + return this; + } + + public void setCreationDate(LocalDate creationDate) { + this.creationDate = creationDate; + } + + public Post getPost() { + return post; + } + + public Comment post(Post post) { + this.post = post; + return this; + } + + public void setPost(Post post) { + this.post = post; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Comment comment = (Comment) o; + if (comment.id == null || id == null) { + return false; + } + return Objects.equals(id, comment.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "Comment{" + + "id=" + id + + ", text='" + text + "'" + + ", creationDate='" + creationDate + "'" + + '}'; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/PersistentAuditEvent.java b/jhipster/src/main/java/com/baeldung/domain/PersistentAuditEvent.java new file mode 100644 index 0000000000..c0fb0cb146 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/PersistentAuditEvent.java @@ -0,0 +1,78 @@ +package com.baeldung.domain; + + +import java.io.Serializable; +import java.time.LocalDateTime; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; + +/** + * Persist AuditEvent managed by the Spring Boot actuator + * @see org.springframework.boot.actuate.audit.AuditEvent + */ +@Entity +@Table(name = "jhi_persistent_audit_event") +public class PersistentAuditEvent implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "event_id") + private Long id; + + @NotNull + @Column(nullable = false) + private String principal; + + @Column(name = "event_date") + private LocalDateTime auditEventDate; + @Column(name = "event_type") + private String auditEventType; + + @ElementCollection + @MapKeyColumn(name = "name") + @Column(name = "value") + @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id")) + private Map data = new HashMap<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public LocalDateTime getAuditEventDate() { + return auditEventDate; + } + + public void setAuditEventDate(LocalDateTime auditEventDate) { + this.auditEventDate = auditEventDate; + } + + public String getAuditEventType() { + return auditEventType; + } + + public void setAuditEventType(String auditEventType) { + this.auditEventType = auditEventType; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/Post.java b/jhipster/src/main/java/com/baeldung/domain/Post.java new file mode 100644 index 0000000000..7f084dc177 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/Post.java @@ -0,0 +1,133 @@ +package com.baeldung.domain; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; + +/** + * A Post. + */ +@Entity +@Table(name = "post") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class Post implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Size(min = 10, max = 100) + @Column(name = "title", length = 100, nullable = false) + private String title; + + @NotNull + @Size(min = 10, max = 1000) + @Column(name = "content", length = 1000, nullable = false) + private String content; + + @NotNull + @Column(name = "creation_date", nullable = false) + private LocalDate creationDate; + + @ManyToOne(optional = false) + @NotNull + private User creator; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public Post title(String title) { + this.title = title; + return this; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public Post content(String content) { + this.content = content; + return this; + } + + public void setContent(String content) { + this.content = content; + } + + public LocalDate getCreationDate() { + return creationDate; + } + + public Post creationDate(LocalDate creationDate) { + this.creationDate = creationDate; + return this; + } + + public void setCreationDate(LocalDate creationDate) { + this.creationDate = creationDate; + } + + public User getCreator() { + return creator; + } + + public Post creator(User user) { + this.creator = user; + return this; + } + + public void setCreator(User user) { + this.creator = user; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Post post = (Post) o; + if (post.id == null || id == null) { + return false; + } + return Objects.equals(id, post.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return "Post{" + + "id=" + id + + ", title='" + title + "'" + + ", content='" + content + "'" + + ", creationDate='" + creationDate + "'" + + '}'; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/User.java b/jhipster/src/main/java/com/baeldung/domain/User.java new file mode 100644 index 0000000000..76aa3a5209 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/User.java @@ -0,0 +1,235 @@ +package com.baeldung.domain; + +import com.baeldung.config.Constants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.validator.constraints.Email; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.time.ZonedDateTime; + +/** + * A user. + */ +@Entity +@Table(name = "jhi_user") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +public class User extends AbstractAuditingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + @Column(length = 50, unique = true, nullable = false) + private String login; + + @JsonIgnore + @NotNull + @Size(min = 60, max = 60) + @Column(name = "password_hash",length = 60) + private String password; + + @Size(max = 50) + @Column(name = "first_name", length = 50) + private String firstName; + + @Size(max = 50) + @Column(name = "last_name", length = 50) + private String lastName; + + @Email + @Size(max = 100) + @Column(length = 100, unique = true) + private String email; + + @NotNull + @Column(nullable = false) + private boolean activated = false; + + @Size(min = 2, max = 5) + @Column(name = "lang_key", length = 5) + private String langKey; + + @Size(max = 256) + @Column(name = "image_url", length = 256) + private String imageUrl; + + @Size(max = 20) + @Column(name = "activation_key", length = 20) + @JsonIgnore + private String activationKey; + + @Size(max = 20) + @Column(name = "reset_key", length = 20) + private String resetKey; + + @Column(name = "reset_date") + private ZonedDateTime resetDate = null; + + @JsonIgnore + @ManyToMany + @JoinTable( + name = "jhi_user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")}) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @BatchSize(size = 20) + private Set authorities = new HashSet<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + //Lowercase the login before saving it in database + public void setLogin(String login) { + this.login = login.toLowerCase(Locale.ENGLISH); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + public boolean getActivated() { + return activated; + } + + public void setActivated(boolean activated) { + this.activated = activated; + } + + public String getActivationKey() { + return activationKey; + } + + public void setActivationKey(String activationKey) { + this.activationKey = activationKey; + } + + public String getResetKey() { + return resetKey; + } + + public void setResetKey(String resetKey) { + this.resetKey = resetKey; + } + + public ZonedDateTime getResetDate() { + return resetDate; + } + + public void setResetDate(ZonedDateTime resetDate) { + this.resetDate = resetDate; + } + + public String getLangKey() { + return langKey; + } + + public void setLangKey(String langKey) { + this.langKey = langKey; + } + + public Set getAuthorities() { + return authorities; + } + + public void setAuthorities(Set authorities) { + this.authorities = authorities; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + User user = (User) o; + + if (!login.equals(user.login)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return login.hashCode(); + } + + @Override + public String toString() { + return "User{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated='" + activated + '\'' + + ", langKey='" + langKey + '\'' + + ", activationKey='" + activationKey + '\'' + + "}"; + } +} diff --git a/jhipster/src/main/java/com/baeldung/domain/package-info.java b/jhipster/src/main/java/com/baeldung/domain/package-info.java new file mode 100644 index 0000000000..2492048c77 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/domain/package-info.java @@ -0,0 +1,4 @@ +/** + * JPA domain objects. + */ +package com.baeldung.domain; diff --git a/jhipster/src/main/java/com/baeldung/repository/AuthorityRepository.java b/jhipster/src/main/java/com/baeldung/repository/AuthorityRepository.java new file mode 100644 index 0000000000..fab63174aa --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/AuthorityRepository.java @@ -0,0 +1,11 @@ +package com.baeldung.repository; + +import com.baeldung.domain.Authority; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Spring Data JPA repository for the Authority entity. + */ +public interface AuthorityRepository extends JpaRepository { +} diff --git a/jhipster/src/main/java/com/baeldung/repository/CommentRepository.java b/jhipster/src/main/java/com/baeldung/repository/CommentRepository.java new file mode 100644 index 0000000000..d2d2618c36 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/CommentRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.repository; + +import com.baeldung.domain.Comment; + +import org.springframework.data.jpa.repository.*; + +import java.util.List; + +/** + * Spring Data JPA repository for the Comment entity. + */ +@SuppressWarnings("unused") +public interface CommentRepository extends JpaRepository { + +} diff --git a/jhipster/src/main/java/com/baeldung/repository/CustomAuditEventRepository.java b/jhipster/src/main/java/com/baeldung/repository/CustomAuditEventRepository.java new file mode 100644 index 0000000000..fcfa9baeec --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/CustomAuditEventRepository.java @@ -0,0 +1,81 @@ +package com.baeldung.repository; + +import com.baeldung.config.Constants; +import com.baeldung.config.audit.AuditEventConverter; +import com.baeldung.domain.PersistentAuditEvent; + +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.AuditEventRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; + +/** + * An implementation of Spring Boot's AuditEventRepository. + */ +@Repository +public class CustomAuditEventRepository implements AuditEventRepository { + + private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + public CustomAuditEventRepository(PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + @Override + public List find(Date after) { + Iterable persistentAuditEvents = + persistenceAuditEventRepository.findByAuditEventDateAfter(LocalDateTime.from(after.toInstant())); + return auditEventConverter.convertToAuditEvent(persistentAuditEvents); + } + + @Override + public List find(String principal, Date after) { + Iterable persistentAuditEvents; + if (principal == null && after == null) { + persistentAuditEvents = persistenceAuditEventRepository.findAll(); + } else if (after == null) { + persistentAuditEvents = persistenceAuditEventRepository.findByPrincipal(principal); + } else { + persistentAuditEvents = + persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfter(principal, LocalDateTime.from(after.toInstant())); + } + return auditEventConverter.convertToAuditEvent(persistentAuditEvents); + } + + @Override + public List find(String principal, Date after, String type) { + Iterable persistentAuditEvents = + persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, LocalDateTime.from(after.toInstant()), type); + return auditEventConverter.convertToAuditEvent(persistentAuditEvents); + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void add(AuditEvent event) { + if (!AUTHORIZATION_FAILURE.equals(event.getType()) && + !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { + + PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); + persistentAuditEvent.setPrincipal(event.getPrincipal()); + persistentAuditEvent.setAuditEventType(event.getType()); + Instant instant = Instant.ofEpochMilli(event.getTimestamp().getTime()); + persistentAuditEvent.setAuditEventDate(LocalDateTime.ofInstant(instant, ZoneId.systemDefault())); + persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData())); + persistenceAuditEventRepository.save(persistentAuditEvent); + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/repository/PersistenceAuditEventRepository.java b/jhipster/src/main/java/com/baeldung/repository/PersistenceAuditEventRepository.java new file mode 100644 index 0000000000..f4b7f1c5bf --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/PersistenceAuditEventRepository.java @@ -0,0 +1,26 @@ +package com.baeldung.repository; + +import com.baeldung.domain.PersistentAuditEvent; + +import java.time.LocalDateTime; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +/** + * Spring Data JPA repository for the PersistentAuditEvent entity. + */ +public interface PersistenceAuditEventRepository extends JpaRepository { + + List findByPrincipal(String principal); + + List findByAuditEventDateAfter(LocalDateTime after); + + List findByPrincipalAndAuditEventDateAfter(String principal, LocalDateTime after); + + List findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principle, LocalDateTime after, String type); + + Page findAllByAuditEventDateBetween(LocalDateTime fromDate, LocalDateTime toDate, Pageable pageable); +} diff --git a/jhipster/src/main/java/com/baeldung/repository/PostRepository.java b/jhipster/src/main/java/com/baeldung/repository/PostRepository.java new file mode 100644 index 0000000000..22e8aa1372 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/PostRepository.java @@ -0,0 +1,18 @@ +package com.baeldung.repository; + +import com.baeldung.domain.Post; + +import org.springframework.data.jpa.repository.*; + +import java.util.List; + +/** + * Spring Data JPA repository for the Post entity. + */ +@SuppressWarnings("unused") +public interface PostRepository extends JpaRepository { + + @Query("select post from Post post where post.creator.login = ?#{principal.username}") + List findByCreatorIsCurrentUser(); + +} diff --git a/jhipster/src/main/java/com/baeldung/repository/UserRepository.java b/jhipster/src/main/java/com/baeldung/repository/UserRepository.java new file mode 100644 index 0000000000..a8f8149910 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/UserRepository.java @@ -0,0 +1,37 @@ +package com.baeldung.repository; + +import com.baeldung.domain.User; + +import java.time.ZonedDateTime; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +/** + * Spring Data JPA repository for the User entity. + */ +public interface UserRepository extends JpaRepository { + + Optional findOneByActivationKey(String activationKey); + + List findAllByActivatedIsFalseAndCreatedDateBefore(ZonedDateTime dateTime); + + Optional findOneByResetKey(String resetKey); + + Optional findOneByEmail(String email); + + Optional findOneByLogin(String login); + + @EntityGraph(attributePaths = "authorities") + User findOneWithAuthoritiesById(Long id); + + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByLogin(String login); + + Page findAllByLoginNot(Pageable pageable, String login); +} diff --git a/jhipster/src/main/java/com/baeldung/repository/package-info.java b/jhipster/src/main/java/com/baeldung/repository/package-info.java new file mode 100644 index 0000000000..9d1fb837c3 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/repository/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Data JPA repositories. + */ +package com.baeldung.repository; diff --git a/jhipster/src/main/java/com/baeldung/security/AuthoritiesConstants.java b/jhipster/src/main/java/com/baeldung/security/AuthoritiesConstants.java new file mode 100644 index 0000000000..40cf54e4f6 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/AuthoritiesConstants.java @@ -0,0 +1,16 @@ +package com.baeldung.security; + +/** + * Constants for Spring Security authorities. + */ +public final class AuthoritiesConstants { + + public static final String ADMIN = "ROLE_ADMIN"; + + public static final String USER = "ROLE_USER"; + + public static final String ANONYMOUS = "ROLE_ANONYMOUS"; + + private AuthoritiesConstants() { + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/DomainUserDetailsService.java b/jhipster/src/main/java/com/baeldung/security/DomainUserDetailsService.java new file mode 100644 index 0000000000..6ce07739f7 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/DomainUserDetailsService.java @@ -0,0 +1,51 @@ +package com.baeldung.security; + +import com.baeldung.domain.User; +import com.baeldung.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Authenticate a user from the database. + */ +@Component("userDetailsService") +public class DomainUserDetailsService implements UserDetailsService { + + private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); + + private final UserRepository userRepository; + + public DomainUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String login) { + log.debug("Authenticating {}", login); + String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); + Optional userFromDatabase = userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin); + return userFromDatabase.map(user -> { + if (!user.getActivated()) { + throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); + } + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getName())) + .collect(Collectors.toList()); + return new org.springframework.security.core.userdetails.User(lowercaseLogin, + user.getPassword(), + grantedAuthorities); + }).orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " + + "database")); + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/SecurityUtils.java b/jhipster/src/main/java/com/baeldung/security/SecurityUtils.java new file mode 100644 index 0000000000..96aaef3805 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/SecurityUtils.java @@ -0,0 +1,68 @@ +package com.baeldung.security; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * Utility class for Spring Security. + */ +public final class SecurityUtils { + + private SecurityUtils() { + } + + /** + * Get the login of the current user. + * + * @return the login of the current user + */ + public static String getCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + Authentication authentication = securityContext.getAuthentication(); + String userName = null; + if (authentication != null) { + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + userName = springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + userName = (String) authentication.getPrincipal(); + } + } + return userName; + } + + /** + * Check if a user is authenticated. + * + * @return true if the user is authenticated, false otherwise + */ + public static boolean isAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + Authentication authentication = securityContext.getAuthentication(); + if (authentication != null) { + return authentication.getAuthorities().stream() + .noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS)); + } + return false; + } + + /** + * If the current user has a specific authority (security role). + * + *

The name of this method comes from the isUserInRole() method in the Servlet API

+ * + * @param authority the authority to check + * @return true if the current user has the authority, false otherwise + */ + public static boolean isCurrentUserInRole(String authority) { + SecurityContext securityContext = SecurityContextHolder.getContext(); + Authentication authentication = securityContext.getAuthentication(); + if (authentication != null) { + return authentication.getAuthorities().stream() + .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority)); + } + return false; + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/SpringSecurityAuditorAware.java b/jhipster/src/main/java/com/baeldung/security/SpringSecurityAuditorAware.java new file mode 100644 index 0000000000..d59917153c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/SpringSecurityAuditorAware.java @@ -0,0 +1,19 @@ +package com.baeldung.security; + +import com.baeldung.config.Constants; + +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; + +/** + * Implementation of AuditorAware based on Spring Security. + */ +@Component +public class SpringSecurityAuditorAware implements AuditorAware { + + @Override + public String getCurrentAuditor() { + String userName = SecurityUtils.getCurrentUserLogin(); + return userName != null ? userName : Constants.SYSTEM_ACCOUNT; + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/UserNotActivatedException.java b/jhipster/src/main/java/com/baeldung/security/UserNotActivatedException.java new file mode 100644 index 0000000000..7265188cad --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/UserNotActivatedException.java @@ -0,0 +1,19 @@ +package com.baeldung.security; + +import org.springframework.security.core.AuthenticationException; + +/** + * This exception is thrown in case of a not activated user trying to authenticate. + */ +public class UserNotActivatedException extends AuthenticationException { + + private static final long serialVersionUID = 1L; + + public UserNotActivatedException(String message) { + super(message); + } + + public UserNotActivatedException(String message, Throwable t) { + super(message, t); + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/jwt/JWTConfigurer.java b/jhipster/src/main/java/com/baeldung/security/jwt/JWTConfigurer.java new file mode 100644 index 0000000000..5720812b9f --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/jwt/JWTConfigurer.java @@ -0,0 +1,23 @@ +package com.baeldung.security.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JWTConfigurer extends SecurityConfigurerAdapter { + + public static final String AUTHORIZATION_HEADER = "Authorization"; + + private TokenProvider tokenProvider; + + public JWTConfigurer(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) throws Exception { + JWTFilter customFilter = new JWTFilter(tokenProvider); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/jwt/JWTFilter.java b/jhipster/src/main/java/com/baeldung/security/jwt/JWTFilter.java new file mode 100644 index 0000000000..89b1947e05 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/jwt/JWTFilter.java @@ -0,0 +1,58 @@ +package com.baeldung.security.jwt; + +import java.io.IOException; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import io.jsonwebtoken.ExpiredJwtException; + +/** + * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is + * found. + */ +public class JWTFilter extends GenericFilterBean { + + private final Logger log = LoggerFactory.getLogger(JWTFilter.class); + + private TokenProvider tokenProvider; + + public JWTFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + try { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) { + Authentication authentication = this.tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(servletRequest, servletResponse); + } catch (ExpiredJwtException eje) { + log.info("Security exception for user {} - {}", + eje.getClaims().getSubject(), eje.getMessage()); + + log.trace("Security exception trace: {}", eje); + ((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + } + + private String resolveToken(HttpServletRequest request){ + String bearerToken = request.getHeader(JWTConfigurer.AUTHORIZATION_HEADER); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7, bearerToken.length()); + } + return null; + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/jwt/TokenProvider.java b/jhipster/src/main/java/com/baeldung/security/jwt/TokenProvider.java new file mode 100644 index 0000000000..3ba4d7c793 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/jwt/TokenProvider.java @@ -0,0 +1,109 @@ +package com.baeldung.security.jwt; + +import io.github.jhipster.config.JHipsterProperties; + +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import io.jsonwebtoken.*; + +@Component +public class TokenProvider { + + private final Logger log = LoggerFactory.getLogger(TokenProvider.class); + + private static final String AUTHORITIES_KEY = "auth"; + + private String secretKey; + + private long tokenValidityInMilliseconds; + + private long tokenValidityInMillisecondsForRememberMe; + + private final JHipsterProperties jHipsterProperties; + + public TokenProvider(JHipsterProperties jHipsterProperties) { + this.jHipsterProperties = jHipsterProperties; + } + + @PostConstruct + public void init() { + this.secretKey = + jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret(); + + this.tokenValidityInMilliseconds = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds(); + this.tokenValidityInMillisecondsForRememberMe = + 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe(); + } + + public String createToken(Authentication authentication, Boolean rememberMe) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity; + if (rememberMe) { + validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe); + } else { + validity = new Date(now + this.tokenValidityInMilliseconds); + } + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(SignatureAlgorithm.HS512, secretKey) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts.parser() + .setSigningKey(secretKey) + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, "", authorities); + } + + public boolean validateToken(String authToken) { + try { + Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken); + return true; + } catch (SignatureException e) { + log.info("Invalid JWT signature."); + log.trace("Invalid JWT signature trace: {}", e); + } catch (MalformedJwtException e) { + log.info("Invalid JWT token."); + log.trace("Invalid JWT token trace: {}", e); + } catch (ExpiredJwtException e) { + log.info("Expired JWT token."); + log.trace("Expired JWT token trace: {}", e); + } catch (UnsupportedJwtException e) { + log.info("Unsupported JWT token."); + log.trace("Unsupported JWT token trace: {}", e); + } catch (IllegalArgumentException e) { + log.info("JWT token compact of handler are invalid."); + log.trace("JWT token compact of handler are invalid trace: {}", e); + } + return false; + } +} diff --git a/jhipster/src/main/java/com/baeldung/security/package-info.java b/jhipster/src/main/java/com/baeldung/security/package-info.java new file mode 100644 index 0000000000..1e29c15b4e --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/security/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring Security configuration. + */ +package com.baeldung.security; diff --git a/jhipster/src/main/java/com/baeldung/service/AuditEventService.java b/jhipster/src/main/java/com/baeldung/service/AuditEventService.java new file mode 100644 index 0000000000..8701854922 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/AuditEventService.java @@ -0,0 +1,50 @@ +package com.baeldung.service; + +import com.baeldung.config.audit.AuditEventConverter; +import com.baeldung.repository.PersistenceAuditEventRepository; +import java.time.LocalDateTime; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +/** + * Service for managing audit events. + *

+ * This is the default implementation to support SpringBoot Actuator AuditEventRepository + *

+ */ +@Service +@Transactional +public class AuditEventService { + + private final PersistenceAuditEventRepository persistenceAuditEventRepository; + + private final AuditEventConverter auditEventConverter; + + public AuditEventService( + PersistenceAuditEventRepository persistenceAuditEventRepository, + AuditEventConverter auditEventConverter) { + + this.persistenceAuditEventRepository = persistenceAuditEventRepository; + this.auditEventConverter = auditEventConverter; + } + + public Page findAll(Pageable pageable) { + return persistenceAuditEventRepository.findAll(pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Page findByDates(LocalDateTime fromDate, LocalDateTime toDate, Pageable pageable) { + return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable) + .map(auditEventConverter::convertToAuditEvent); + } + + public Optional find(Long id) { + return Optional.ofNullable(persistenceAuditEventRepository.findOne(id)).map + (auditEventConverter::convertToAuditEvent); + } +} diff --git a/jhipster/src/main/java/com/baeldung/service/MailService.java b/jhipster/src/main/java/com/baeldung/service/MailService.java new file mode 100644 index 0000000000..9f85531da7 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/MailService.java @@ -0,0 +1,108 @@ +package com.baeldung.service; + +import com.baeldung.domain.User; + +import io.github.jhipster.config.JHipsterProperties; + +import org.apache.commons.lang3.CharEncoding; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring4.SpringTemplateEngine; + +import javax.mail.internet.MimeMessage; +import java.util.Locale; + +/** + * Service for sending e-mails. + *

+ * We use the @Async annotation to send e-mails asynchronously. + *

+ */ +@Service +public class MailService { + + private final Logger log = LoggerFactory.getLogger(MailService.class); + + private static final String USER = "user"; + + private static final String BASE_URL = "baseUrl"; + + private final JHipsterProperties jHipsterProperties; + + private final JavaMailSender javaMailSender; + + private final MessageSource messageSource; + + private final SpringTemplateEngine templateEngine; + + public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender, + MessageSource messageSource, SpringTemplateEngine templateEngine) { + + this.jHipsterProperties = jHipsterProperties; + this.javaMailSender = javaMailSender; + this.messageSource = messageSource; + this.templateEngine = templateEngine; + } + + @Async + public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) { + log.debug("Send e-mail[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, isHtml, to, subject, content); + + // Prepare message using a Spring helper + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + try { + MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8); + message.setTo(to); + message.setFrom(jHipsterProperties.getMail().getFrom()); + message.setSubject(subject); + message.setText(content, isHtml); + javaMailSender.send(mimeMessage); + log.debug("Sent e-mail to User '{}'", to); + } catch (Exception e) { + log.warn("E-mail could not be sent to user '{}'", to, e); + } + } + + @Async + public void sendActivationEmail(User user) { + log.debug("Sending activation e-mail to '{}'", user.getEmail()); + Locale locale = Locale.forLanguageTag(user.getLangKey()); + Context context = new Context(locale); + context.setVariable(USER, user); + context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); + String content = templateEngine.process("activationEmail", context); + String subject = messageSource.getMessage("email.activation.title", null, locale); + sendEmail(user.getEmail(), subject, content, false, true); + } + + @Async + public void sendCreationEmail(User user) { + log.debug("Sending creation e-mail to '{}'", user.getEmail()); + Locale locale = Locale.forLanguageTag(user.getLangKey()); + Context context = new Context(locale); + context.setVariable(USER, user); + context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); + String content = templateEngine.process("creationEmail", context); + String subject = messageSource.getMessage("email.activation.title", null, locale); + sendEmail(user.getEmail(), subject, content, false, true); + } + + @Async + public void sendPasswordResetMail(User user) { + log.debug("Sending password reset e-mail to '{}'", user.getEmail()); + Locale locale = Locale.forLanguageTag(user.getLangKey()); + Context context = new Context(locale); + context.setVariable(USER, user); + context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl()); + String content = templateEngine.process("passwordResetEmail", context); + String subject = messageSource.getMessage("email.reset.title", null, locale); + sendEmail(user.getEmail(), subject, content, false, true); + } +} diff --git a/jhipster/src/main/java/com/baeldung/service/UserService.java b/jhipster/src/main/java/com/baeldung/service/UserService.java new file mode 100644 index 0000000000..7b9096e0da --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/UserService.java @@ -0,0 +1,228 @@ +package com.baeldung.service; + +import com.baeldung.domain.Authority; +import com.baeldung.domain.User; +import com.baeldung.repository.AuthorityRepository; +import com.baeldung.config.Constants; +import com.baeldung.repository.UserRepository; +import com.baeldung.security.AuthoritiesConstants; +import com.baeldung.security.SecurityUtils; +import com.baeldung.service.util.RandomUtil; +import com.baeldung.service.dto.UserDTO; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.ZonedDateTime; +import java.util.*; + +/** + * Service class for managing users. + */ +@Service +@Transactional +public class UserService { + + private final Logger log = LoggerFactory.getLogger(UserService.class); + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + + private final AuthorityRepository authorityRepository; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.authorityRepository = authorityRepository; + } + + public Optional activateRegistration(String key) { + log.debug("Activating user for activation key {}", key); + return userRepository.findOneByActivationKey(key) + .map(user -> { + // activate given user for the registration key. + user.setActivated(true); + user.setActivationKey(null); + log.debug("Activated user: {}", user); + return user; + }); + } + + public Optional completePasswordReset(String newPassword, String key) { + log.debug("Reset user password for reset key {}", key); + + return userRepository.findOneByResetKey(key) + .filter(user -> { + ZonedDateTime oneDayAgo = ZonedDateTime.now().minusHours(24); + return user.getResetDate().isAfter(oneDayAgo); + }) + .map(user -> { + user.setPassword(passwordEncoder.encode(newPassword)); + user.setResetKey(null); + user.setResetDate(null); + return user; + }); + } + + public Optional requestPasswordReset(String mail) { + return userRepository.findOneByEmail(mail) + .filter(User::getActivated) + .map(user -> { + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(ZonedDateTime.now()); + return user; + }); + } + + public User createUser(String login, String password, String firstName, String lastName, String email, + String imageUrl, String langKey) { + + User newUser = new User(); + Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER); + Set authorities = new HashSet<>(); + String encryptedPassword = passwordEncoder.encode(password); + newUser.setLogin(login); + // new user gets initially a generated password + newUser.setPassword(encryptedPassword); + newUser.setFirstName(firstName); + newUser.setLastName(lastName); + newUser.setEmail(email); + newUser.setImageUrl(imageUrl); + newUser.setLangKey(langKey); + // new user is not active + newUser.setActivated(false); + // new user gets registration key + newUser.setActivationKey(RandomUtil.generateActivationKey()); + authorities.add(authority); + newUser.setAuthorities(authorities); + userRepository.save(newUser); + log.debug("Created Information for User: {}", newUser); + return newUser; + } + + public User createUser(UserDTO userDTO) { + User user = new User(); + user.setLogin(userDTO.getLogin()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail()); + user.setImageUrl(userDTO.getImageUrl()); + if (userDTO.getLangKey() == null) { + user.setLangKey("en"); // default language + } else { + user.setLangKey(userDTO.getLangKey()); + } + if (userDTO.getAuthorities() != null) { + Set authorities = new HashSet<>(); + userDTO.getAuthorities().forEach( + authority -> authorities.add(authorityRepository.findOne(authority)) + ); + user.setAuthorities(authorities); + } + String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); + user.setPassword(encryptedPassword); + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(ZonedDateTime.now()); + user.setActivated(true); + userRepository.save(user); + log.debug("Created Information for User: {}", user); + return user; + } + + /** + * Update basic information (first name, last name, email, language) for the current user. + */ + public void updateUser(String firstName, String lastName, String email, String langKey) { + userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(user -> { + user.setFirstName(firstName); + user.setLastName(lastName); + user.setEmail(email); + user.setLangKey(langKey); + log.debug("Changed Information for User: {}", user); + }); + } + + /** + * Update all information for a specific user, and return the modified user. + */ + public Optional updateUser(UserDTO userDTO) { + return Optional.of(userRepository + .findOne(userDTO.getId())) + .map(user -> { + user.setLogin(userDTO.getLogin()); + user.setFirstName(userDTO.getFirstName()); + user.setLastName(userDTO.getLastName()); + user.setEmail(userDTO.getEmail()); + user.setImageUrl(userDTO.getImageUrl()); + user.setActivated(userDTO.isActivated()); + user.setLangKey(userDTO.getLangKey()); + Set managedAuthorities = user.getAuthorities(); + managedAuthorities.clear(); + userDTO.getAuthorities().stream() + .map(authorityRepository::findOne) + .forEach(managedAuthorities::add); + log.debug("Changed Information for User: {}", user); + return user; + }) + .map(UserDTO::new); + } + + public void deleteUser(String login) { + userRepository.findOneByLogin(login).ifPresent(user -> { + userRepository.delete(user); + log.debug("Deleted User: {}", user); + }); + } + + public void changePassword(String password) { + userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(user -> { + String encryptedPassword = passwordEncoder.encode(password); + user.setPassword(encryptedPassword); + log.debug("Changed password for User: {}", user); + }); + } + + @Transactional(readOnly = true) + public Page getAllManagedUsers(Pageable pageable) { + return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new); + } + + @Transactional(readOnly = true) + public Optional getUserWithAuthoritiesByLogin(String login) { + return userRepository.findOneWithAuthoritiesByLogin(login); + } + + @Transactional(readOnly = true) + public User getUserWithAuthorities(Long id) { + return userRepository.findOneWithAuthoritiesById(id); + } + + @Transactional(readOnly = true) + public User getUserWithAuthorities() { + return userRepository.findOneWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin()).orElse(null); + } + + + /** + * Not activated users should be automatically deleted after 3 days. + *

+ * This is scheduled to get fired everyday, at 01:00 (am). + *

+ */ + @Scheduled(cron = "0 0 1 * * ?") + public void removeNotActivatedUsers() { + ZonedDateTime now = ZonedDateTime.now(); + List users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minusDays(3)); + for (User user : users) { + log.debug("Deleting not activated user {}", user.getLogin()); + userRepository.delete(user); + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/service/dto/UserDTO.java b/jhipster/src/main/java/com/baeldung/service/dto/UserDTO.java new file mode 100644 index 0000000000..1080bab7b8 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/dto/UserDTO.java @@ -0,0 +1,167 @@ +package com.baeldung.service.dto; + +import com.baeldung.config.Constants; + +import com.baeldung.domain.Authority; +import com.baeldung.domain.User; + +import org.hibernate.validator.constraints.Email; + +import javax.validation.constraints.*; +import java.time.ZonedDateTime; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A DTO representing a user, with his authorities. + */ +public class UserDTO { + + private Long id; + + @Pattern(regexp = Constants.LOGIN_REGEX) + @Size(min = 1, max = 50) + private String login; + + @Size(max = 50) + private String firstName; + + @Size(max = 50) + private String lastName; + + @Email + @Size(min = 5, max = 100) + private String email; + + @Size(max = 256) + private String imageUrl; + + private boolean activated = false; + + @Size(min = 2, max = 5) + private String langKey; + + private String createdBy; + + private ZonedDateTime createdDate; + + private String lastModifiedBy; + + private ZonedDateTime lastModifiedDate; + + private Set authorities; + + public UserDTO() { + // Empty constructor needed for MapStruct. + } + + public UserDTO(User user) { + this(user.getId(), user.getLogin(), user.getFirstName(), user.getLastName(), + user.getEmail(), user.getActivated(), user.getImageUrl(), user.getLangKey(), + user.getCreatedBy(), user.getCreatedDate(), user.getLastModifiedBy(), user.getLastModifiedDate(), + user.getAuthorities().stream().map(Authority::getName) + .collect(Collectors.toSet())); + } + + public UserDTO(Long id, String login, String firstName, String lastName, + String email, boolean activated, String imageUrl, String langKey, + String createdBy, ZonedDateTime createdDate, String lastModifiedBy, ZonedDateTime lastModifiedDate, + Set authorities) { + + this.id = id; + this.login = login; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.activated = activated; + this.imageUrl = imageUrl; + this.langKey = langKey; + this.createdBy = createdBy; + this.createdDate = createdDate; + this.lastModifiedBy = lastModifiedBy; + this.lastModifiedDate = lastModifiedDate; + this.authorities = authorities; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getEmail() { + return email; + } + + public String getImageUrl() { + return imageUrl; + } + + public boolean isActivated() { + return activated; + } + + public String getLangKey() { + return langKey; + } + + public String getCreatedBy() { + return createdBy; + } + + public ZonedDateTime getCreatedDate() { + return createdDate; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public ZonedDateTime getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public Set getAuthorities() { + return authorities; + } + + @Override + public String toString() { + return "UserDTO{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", imageUrl='" + imageUrl + '\'' + + ", activated=" + activated + + ", langKey='" + langKey + '\'' + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastModifiedBy='" + lastModifiedBy + '\'' + + ", lastModifiedDate=" + lastModifiedDate + + ", authorities=" + authorities + + "}"; + } +} diff --git a/jhipster/src/main/java/com/baeldung/service/dto/package-info.java b/jhipster/src/main/java/com/baeldung/service/dto/package-info.java new file mode 100644 index 0000000000..12d048eb7a --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/dto/package-info.java @@ -0,0 +1,4 @@ +/** + * Data Transfer Objects. + */ +package com.baeldung.service.dto; diff --git a/jhipster/src/main/java/com/baeldung/service/mapper/UserMapper.java b/jhipster/src/main/java/com/baeldung/service/mapper/UserMapper.java new file mode 100644 index 0000000000..aaada37162 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/mapper/UserMapper.java @@ -0,0 +1,55 @@ +package com.baeldung.service.mapper; + +import com.baeldung.domain.Authority; +import com.baeldung.domain.User; +import com.baeldung.service.dto.UserDTO; +import org.mapstruct.*; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Mapper for the entity User and its DTO UserDTO. + */ +@Mapper(componentModel = "spring", uses = {}) +public interface UserMapper { + + UserDTO userToUserDTO(User user); + + List usersToUserDTOs(List users); + + @Mapping(target = "createdBy", ignore = true) + @Mapping(target = "createdDate", ignore = true) + @Mapping(target = "lastModifiedBy", ignore = true) + @Mapping(target = "lastModifiedDate", ignore = true) + @Mapping(target = "activationKey", ignore = true) + @Mapping(target = "resetKey", ignore = true) + @Mapping(target = "resetDate", ignore = true) + @Mapping(target = "password", ignore = true) + User userDTOToUser(UserDTO userDTO); + + List userDTOsToUsers(List userDTOs); + + default User userFromId(Long id) { + if (id == null) { + return null; + } + User user = new User(); + user.setId(id); + return user; + } + + default Set stringsFromAuthorities (Set authorities) { + return authorities.stream().map(Authority::getName) + .collect(Collectors.toSet()); + } + + default Set authoritiesFromStrings(Set strings) { + return strings.stream().map(string -> { + Authority auth = new Authority(); + auth.setName(string); + return auth; + }).collect(Collectors.toSet()); + } +} diff --git a/jhipster/src/main/java/com/baeldung/service/mapper/package-info.java b/jhipster/src/main/java/com/baeldung/service/mapper/package-info.java new file mode 100644 index 0000000000..75f8d24f08 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/mapper/package-info.java @@ -0,0 +1,4 @@ +/** + * MapStruct mappers for mapping domain objects and Data Transfer Objects. + */ +package com.baeldung.service.mapper; diff --git a/jhipster/src/main/java/com/baeldung/service/package-info.java b/jhipster/src/main/java/com/baeldung/service/package-info.java new file mode 100644 index 0000000000..0695bc1473 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/package-info.java @@ -0,0 +1,4 @@ +/** + * Service layer beans. + */ +package com.baeldung.service; diff --git a/jhipster/src/main/java/com/baeldung/service/util/RandomUtil.java b/jhipster/src/main/java/com/baeldung/service/util/RandomUtil.java new file mode 100644 index 0000000000..1f4d9f8b5d --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/service/util/RandomUtil.java @@ -0,0 +1,41 @@ +package com.baeldung.service.util; + +import org.apache.commons.lang3.RandomStringUtils; + +/** + * Utility class for generating random Strings. + */ +public final class RandomUtil { + + private static final int DEF_COUNT = 20; + + private RandomUtil() { + } + + /** + * Generate a password. + * + * @return the generated password + */ + public static String generatePassword() { + return RandomStringUtils.randomAlphanumeric(DEF_COUNT); + } + + /** + * Generate an activation key. + * + * @return the generated activation key + */ + public static String generateActivationKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } + + /** + * Generate a reset key. + * + * @return the generated reset key + */ + public static String generateResetKey() { + return RandomStringUtils.randomNumeric(DEF_COUNT); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/AccountResource.java b/jhipster/src/main/java/com/baeldung/web/rest/AccountResource.java new file mode 100644 index 0000000000..c1009fc918 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/AccountResource.java @@ -0,0 +1,202 @@ +package com.baeldung.web.rest; + +import com.codahale.metrics.annotation.Timed; + +import com.baeldung.domain.User; +import com.baeldung.repository.UserRepository; +import com.baeldung.security.SecurityUtils; +import com.baeldung.service.MailService; +import com.baeldung.service.UserService; +import com.baeldung.service.dto.UserDTO; +import com.baeldung.web.rest.vm.KeyAndPasswordVM; +import com.baeldung.web.rest.vm.ManagedUserVM; +import com.baeldung.web.rest.util.HeaderUtil; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.*; + +/** + * REST controller for managing the current user's account. + */ +@RestController +@RequestMapping("/api") +public class AccountResource { + + private final Logger log = LoggerFactory.getLogger(AccountResource.class); + + private final UserRepository userRepository; + + private final UserService userService; + + private final MailService mailService; + + public AccountResource(UserRepository userRepository, UserService userService, + MailService mailService) { + + this.userRepository = userRepository; + this.userService = userService; + this.mailService = mailService; + } + + /** + * POST /register : register the user. + * + * @param managedUserVM the managed user View Model + * @return the ResponseEntity with status 201 (Created) if the user is registered or 400 (Bad Request) if the login or e-mail is already in use + */ + @PostMapping(path = "/register", + produces={MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE}) + @Timed + public ResponseEntity registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) { + + HttpHeaders textPlainHeaders = new HttpHeaders(); + textPlainHeaders.setContentType(MediaType.TEXT_PLAIN); + + return userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()) + .map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST)) + .orElseGet(() -> userRepository.findOneByEmail(managedUserVM.getEmail()) + .map(user -> new ResponseEntity<>("e-mail address already in use", textPlainHeaders, HttpStatus.BAD_REQUEST)) + .orElseGet(() -> { + User user = userService + .createUser(managedUserVM.getLogin(), managedUserVM.getPassword(), + managedUserVM.getFirstName(), managedUserVM.getLastName(), + managedUserVM.getEmail().toLowerCase(), managedUserVM.getImageUrl(), managedUserVM.getLangKey()); + + mailService.sendActivationEmail(user); + return new ResponseEntity<>(HttpStatus.CREATED); + }) + ); + } + + /** + * GET /activate : activate the registered user. + * + * @param key the activation key + * @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 (Internal Server Error) if the user couldn't be activated + */ + @GetMapping("/activate") + @Timed + public ResponseEntity activateAccount(@RequestParam(value = "key") String key) { + return userService.activateRegistration(key) + .map(user -> new ResponseEntity(HttpStatus.OK)) + .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + + /** + * GET /authenticate : check if the user is authenticated, and return its login. + * + * @param request the HTTP request + * @return the login if the user is authenticated + */ + @GetMapping("/authenticate") + @Timed + public String isAuthenticated(HttpServletRequest request) { + log.debug("REST request to check if the current user is authenticated"); + return request.getRemoteUser(); + } + + /** + * GET /account : get the current user. + * + * @return the ResponseEntity with status 200 (OK) and the current user in body, or status 500 (Internal Server Error) if the user couldn't be returned + */ + @GetMapping("/account") + @Timed + public ResponseEntity getAccount() { + return Optional.ofNullable(userService.getUserWithAuthorities()) + .map(user -> new ResponseEntity<>(new UserDTO(user), HttpStatus.OK)) + .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + + /** + * POST /account : update the current user information. + * + * @param userDTO the current user information + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal Server Error) if the user couldn't be updated + */ + @PostMapping("/account") + @Timed + public ResponseEntity saveAccount(@Valid @RequestBody UserDTO userDTO) { + Optional existingUser = userRepository.findOneByEmail(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userDTO.getLogin()))) { + return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert("user-management", "emailexists", "Email already in use")).body(null); + } + return userRepository + .findOneByLogin(SecurityUtils.getCurrentUserLogin()) + .map(u -> { + userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), + userDTO.getLangKey()); + return new ResponseEntity(HttpStatus.OK); + }) + .orElseGet(() -> new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + + /** + * POST /account/change_password : changes the current user's password + * + * @param password the new password + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new password is not strong enough + */ + @PostMapping(path = "/account/change_password", + produces = MediaType.TEXT_PLAIN_VALUE) + @Timed + public ResponseEntity changePassword(@RequestBody String password) { + if (!checkPasswordLength(password)) { + return new ResponseEntity<>("Incorrect password", HttpStatus.BAD_REQUEST); + } + userService.changePassword(password); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * POST /account/reset_password/init : Send an e-mail to reset the password of the user + * + * @param mail the mail of the user + * @return the ResponseEntity with status 200 (OK) if the e-mail was sent, or status 400 (Bad Request) if the e-mail address is not registered + */ + @PostMapping(path = "/account/reset_password/init", + produces = MediaType.TEXT_PLAIN_VALUE) + @Timed + public ResponseEntity requestPasswordReset(@RequestBody String mail) { + return userService.requestPasswordReset(mail) + .map(user -> { + mailService.sendPasswordResetMail(user); + return new ResponseEntity<>("e-mail was sent", HttpStatus.OK); + }).orElse(new ResponseEntity<>("e-mail address not registered", HttpStatus.BAD_REQUEST)); + } + + /** + * POST /account/reset_password/finish : Finish to reset the password of the user + * + * @param keyAndPassword the generated key and the new password + * @return the ResponseEntity with status 200 (OK) if the password has been reset, + * or status 400 (Bad Request) or 500 (Internal Server Error) if the password could not be reset + */ + @PostMapping(path = "/account/reset_password/finish", + produces = MediaType.TEXT_PLAIN_VALUE) + @Timed + public ResponseEntity finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) { + if (!checkPasswordLength(keyAndPassword.getNewPassword())) { + return new ResponseEntity<>("Incorrect password", HttpStatus.BAD_REQUEST); + } + return userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()) + .map(user -> new ResponseEntity(HttpStatus.OK)) + .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); + } + + private boolean checkPasswordLength(String password) { + return !StringUtils.isEmpty(password) && + password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH && + password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/AuditResource.java b/jhipster/src/main/java/com/baeldung/web/rest/AuditResource.java new file mode 100644 index 0000000000..3101d134ed --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/AuditResource.java @@ -0,0 +1,76 @@ +package com.baeldung.web.rest; + +import com.baeldung.service.AuditEventService; +import com.baeldung.web.rest.util.PaginationUtil; + +import io.github.jhipster.web.util.ResponseUtil; +import io.swagger.annotations.ApiParam; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URISyntaxException; +import java.time.LocalDate; +import java.util.List; + +/** + * REST controller for getting the audit events. + */ +@RestController +@RequestMapping("/management/audits") +public class AuditResource { + + private final AuditEventService auditEventService; + + public AuditResource(AuditEventService auditEventService) { + this.auditEventService = auditEventService; + } + + /** + * GET /audits : get a page of AuditEvents. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping + public ResponseEntity> getAll(@ApiParam Pageable pageable) { + Page page = auditEventService.findAll(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits : get a page of AuditEvents between the fromDate and toDate. + * + * @param fromDate the start of the time period of AuditEvents to get + * @param toDate the end of the time period of AuditEvents to get + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + + @GetMapping(params = {"fromDate", "toDate"}) + public ResponseEntity> getByDates( + @RequestParam(value = "fromDate") LocalDate fromDate, + @RequestParam(value = "toDate") LocalDate toDate, + @ApiParam Pageable pageable) { + + Page page = auditEventService.findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /audits/:id : get an AuditEvent by id. + * + * @param id the id of the entity to get + * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status 404 (Not Found) + */ + @GetMapping("/{id:.+}") + public ResponseEntity get(@PathVariable Long id) { + return ResponseUtil.wrapOrNotFound(auditEventService.find(id)); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/CommentResource.java b/jhipster/src/main/java/com/baeldung/web/rest/CommentResource.java new file mode 100644 index 0000000000..3e3f13b5e9 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/CommentResource.java @@ -0,0 +1,129 @@ +package com.baeldung.web.rest; + +import com.codahale.metrics.annotation.Timed; +import com.baeldung.domain.Comment; + +import com.baeldung.repository.CommentRepository; +import com.baeldung.web.rest.util.HeaderUtil; +import com.baeldung.web.rest.util.PaginationUtil; +import io.swagger.annotations.ApiParam; +import io.github.jhipster.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing Comment. + */ +@RestController +@RequestMapping("/api") +public class CommentResource { + + private final Logger log = LoggerFactory.getLogger(CommentResource.class); + + private static final String ENTITY_NAME = "comment"; + + private final CommentRepository commentRepository; + + public CommentResource(CommentRepository commentRepository) { + this.commentRepository = commentRepository; + } + + /** + * POST /comments : Create a new comment. + * + * @param comment the comment to create + * @return the ResponseEntity with status 201 (Created) and with body the new comment, or with status 400 (Bad Request) if the comment has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/comments") + @Timed + public ResponseEntity createComment(@Valid @RequestBody Comment comment) throws URISyntaxException { + log.debug("REST request to save Comment : {}", comment); + if (comment.getId() != null) { + return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new comment cannot already have an ID")).body(null); + } + Comment result = commentRepository.save(comment); + return ResponseEntity.created(new URI("/api/comments/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * PUT /comments : Updates an existing comment. + * + * @param comment the comment to update + * @return the ResponseEntity with status 200 (OK) and with body the updated comment, + * or with status 400 (Bad Request) if the comment is not valid, + * or with status 500 (Internal Server Error) if the comment couldnt be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/comments") + @Timed + public ResponseEntity updateComment(@Valid @RequestBody Comment comment) throws URISyntaxException { + log.debug("REST request to update Comment : {}", comment); + if (comment.getId() == null) { + return createComment(comment); + } + Comment result = commentRepository.save(comment); + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, comment.getId().toString())) + .body(result); + } + + /** + * GET /comments : get all the comments. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of comments in body + * @throws URISyntaxException if there is an error to generate the pagination HTTP headers + */ + @GetMapping("/comments") + @Timed + public ResponseEntity> getAllComments(@ApiParam Pageable pageable) { + log.debug("REST request to get a page of Comments"); + Page page = commentRepository.findAll(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/comments"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /comments/:id : get the "id" comment. + * + * @param id the id of the comment to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the comment, or with status 404 (Not Found) + */ + @GetMapping("/comments/{id}") + @Timed + public ResponseEntity getComment(@PathVariable Long id) { + log.debug("REST request to get Comment : {}", id); + Comment comment = commentRepository.findOne(id); + return ResponseUtil.wrapOrNotFound(Optional.ofNullable(comment)); + } + + /** + * DELETE /comments/:id : delete the "id" comment. + * + * @param id the id of the comment to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/comments/{id}") + @Timed + public ResponseEntity deleteComment(@PathVariable Long id) { + log.debug("REST request to delete Comment : {}", id); + commentRepository.delete(id); + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build(); + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/JWTToken.java b/jhipster/src/main/java/com/baeldung/web/rest/JWTToken.java new file mode 100644 index 0000000000..c0804851f3 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/JWTToken.java @@ -0,0 +1,24 @@ +package com.baeldung.web.rest; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Object to return as body in JWT Authentication. + */ +public class JWTToken { + + private String idToken; + + public JWTToken(String idToken) { + this.idToken = idToken; + } + + @JsonProperty("id_token") + public String getIdToken() { + return idToken; + } + + public void setIdToken(String idToken) { + this.idToken = idToken; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/LogsResource.java b/jhipster/src/main/java/com/baeldung/web/rest/LogsResource.java new file mode 100644 index 0000000000..3d556e2609 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/LogsResource.java @@ -0,0 +1,39 @@ +package com.baeldung.web.rest; + +import com.baeldung.web.rest.vm.LoggerVM; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import com.codahale.metrics.annotation.Timed; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Controller for view and managing Log Level at runtime. + */ +@RestController +@RequestMapping("/management") +public class LogsResource { + + @GetMapping("/logs") + @Timed + public List getList() { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + return context.getLoggerList() + .stream() + .map(LoggerVM::new) + .collect(Collectors.toList()); + } + + @PutMapping("/logs") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Timed + public void changeLevel(@RequestBody LoggerVM jsonLogger) { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/PostResource.java b/jhipster/src/main/java/com/baeldung/web/rest/PostResource.java new file mode 100644 index 0000000000..7505e1fa46 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/PostResource.java @@ -0,0 +1,129 @@ +package com.baeldung.web.rest; + +import com.codahale.metrics.annotation.Timed; +import com.baeldung.domain.Post; + +import com.baeldung.repository.PostRepository; +import com.baeldung.web.rest.util.HeaderUtil; +import com.baeldung.web.rest.util.PaginationUtil; +import io.swagger.annotations.ApiParam; +import io.github.jhipster.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing Post. + */ +@RestController +@RequestMapping("/api") +public class PostResource { + + private final Logger log = LoggerFactory.getLogger(PostResource.class); + + private static final String ENTITY_NAME = "post"; + + private final PostRepository postRepository; + + public PostResource(PostRepository postRepository) { + this.postRepository = postRepository; + } + + /** + * POST /posts : Create a new post. + * + * @param post the post to create + * @return the ResponseEntity with status 201 (Created) and with body the new post, or with status 400 (Bad Request) if the post has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/posts") + @Timed + public ResponseEntity createPost(@Valid @RequestBody Post post) throws URISyntaxException { + log.debug("REST request to save Post : {}", post); + if (post.getId() != null) { + return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new post cannot already have an ID")).body(null); + } + Post result = postRepository.save(post); + return ResponseEntity.created(new URI("/api/posts/" + result.getId())) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())) + .body(result); + } + + /** + * PUT /posts : Updates an existing post. + * + * @param post the post to update + * @return the ResponseEntity with status 200 (OK) and with body the updated post, + * or with status 400 (Bad Request) if the post is not valid, + * or with status 500 (Internal Server Error) if the post couldnt be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/posts") + @Timed + public ResponseEntity updatePost(@Valid @RequestBody Post post) throws URISyntaxException { + log.debug("REST request to update Post : {}", post); + if (post.getId() == null) { + return createPost(post); + } + Post result = postRepository.save(post); + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, post.getId().toString())) + .body(result); + } + + /** + * GET /posts : get all the posts. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of posts in body + * @throws URISyntaxException if there is an error to generate the pagination HTTP headers + */ + @GetMapping("/posts") + @Timed + public ResponseEntity> getAllPosts(@ApiParam Pageable pageable) { + log.debug("REST request to get a page of Posts"); + Page page = postRepository.findAll(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/posts"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /posts/:id : get the "id" post. + * + * @param id the id of the post to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the post, or with status 404 (Not Found) + */ + @GetMapping("/posts/{id}") + @Timed + public ResponseEntity getPost(@PathVariable Long id) { + log.debug("REST request to get Post : {}", id); + Post post = postRepository.findOne(id); + return ResponseUtil.wrapOrNotFound(Optional.ofNullable(post)); + } + + /** + * DELETE /posts/:id : delete the "id" post. + * + * @param id the id of the post to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/posts/{id}") + @Timed + public ResponseEntity deletePost(@PathVariable Long id) { + log.debug("REST request to delete Post : {}", id); + postRepository.delete(id); + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build(); + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/ProfileInfoResource.java b/jhipster/src/main/java/com/baeldung/web/rest/ProfileInfoResource.java new file mode 100644 index 0000000000..b5e26c8281 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/ProfileInfoResource.java @@ -0,0 +1,69 @@ +package com.baeldung.web.rest; + +import com.baeldung.config.DefaultProfileUtil; + +import io.github.jhipster.config.JHipsterProperties; + +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Resource to return information about the currently running Spring profiles. + */ +@RestController +@RequestMapping("/api") +public class ProfileInfoResource { + + private final Environment env; + + private final JHipsterProperties jHipsterProperties; + + public ProfileInfoResource(Environment env, JHipsterProperties jHipsterProperties) { + this.env = env; + this.jHipsterProperties = jHipsterProperties; + } + + @GetMapping("/profile-info") + public ProfileInfoVM getActiveProfiles() { + String[] activeProfiles = DefaultProfileUtil.getActiveProfiles(env); + return new ProfileInfoVM(activeProfiles, getRibbonEnv(activeProfiles)); + } + + private String getRibbonEnv(String[] activeProfiles) { + String[] displayOnActiveProfiles = jHipsterProperties.getRibbon().getDisplayOnActiveProfiles(); + if (displayOnActiveProfiles == null) { + return null; + } + List ribbonProfiles = new ArrayList<>(Arrays.asList(displayOnActiveProfiles)); + List springBootProfiles = Arrays.asList(activeProfiles); + ribbonProfiles.retainAll(springBootProfiles); + if (!ribbonProfiles.isEmpty()) { + return ribbonProfiles.get(0); + } + return null; + } + + class ProfileInfoVM { + + private String[] activeProfiles; + + private String ribbonEnv; + + ProfileInfoVM(String[] activeProfiles, String ribbonEnv) { + this.activeProfiles = activeProfiles; + this.ribbonEnv = ribbonEnv; + } + + public String[] getActiveProfiles() { + return activeProfiles; + } + + public String getRibbonEnv() { + return ribbonEnv; + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/UserJWTController.java b/jhipster/src/main/java/com/baeldung/web/rest/UserJWTController.java new file mode 100644 index 0000000000..02b77c51a6 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/UserJWTController.java @@ -0,0 +1,60 @@ +package com.baeldung.web.rest; + +import com.baeldung.security.jwt.JWTConfigurer; +import com.baeldung.security.jwt.TokenProvider; +import com.baeldung.web.rest.vm.LoginVM; + +import java.util.Collections; + +import com.codahale.metrics.annotation.Timed; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +@RestController +@RequestMapping("/api") +public class UserJWTController { + + private final Logger log = LoggerFactory.getLogger(UserJWTController.class); + + private final TokenProvider tokenProvider; + + private final AuthenticationManager authenticationManager; + + public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) { + this.tokenProvider = tokenProvider; + this.authenticationManager = authenticationManager; + } + + @PostMapping("/authenticate") + @Timed + public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM, HttpServletResponse response) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword()); + + try { + Authentication authentication = this.authenticationManager.authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe(); + String jwt = tokenProvider.createToken(authentication, rememberMe); + response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt); + return ResponseEntity.ok(new JWTToken(jwt)); + } catch (AuthenticationException ae) { + log.trace("Authentication exception trace: {}", ae); + return new ResponseEntity<>(Collections.singletonMap("AuthenticationException", + ae.getLocalizedMessage()), HttpStatus.UNAUTHORIZED); + } + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/UserResource.java b/jhipster/src/main/java/com/baeldung/web/rest/UserResource.java new file mode 100644 index 0000000000..296d3e30ba --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/UserResource.java @@ -0,0 +1,187 @@ +package com.baeldung.web.rest; + +import com.baeldung.config.Constants; +import com.codahale.metrics.annotation.Timed; +import com.baeldung.domain.User; +import com.baeldung.repository.UserRepository; +import com.baeldung.security.AuthoritiesConstants; +import com.baeldung.service.MailService; +import com.baeldung.service.UserService; +import com.baeldung.service.dto.UserDTO; +import com.baeldung.web.rest.vm.ManagedUserVM; +import com.baeldung.web.rest.util.HeaderUtil; +import com.baeldung.web.rest.util.PaginationUtil; +import io.github.jhipster.web.util.ResponseUtil; +import io.swagger.annotations.ApiParam; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +/** + * REST controller for managing users. + * + *

This class accesses the User entity, and needs to fetch its collection of authorities.

+ *

+ * For a normal use-case, it would be better to have an eager relationship between User and Authority, + * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join + * which would be good for performance. + *

+ *

+ * We use a View Model and a DTO for 3 reasons: + *

    + *
  • We want to keep a lazy association between the user and the authorities, because people will + * quite often do relationships with the user, and we don't want them to get the authorities all + * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users' + * application because of this use-case.
  • + *
  • Not having an outer join causes n+1 requests to the database. This is not a real issue as + * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests, + * but then all authorities come from the cache, so in fact it's much better than doing an outer join + * (which will get lots of data from the database, for each HTTP call).
  • + *
  • As this manages users, for security reasons, we'd rather have a DTO layer.
  • + *
+ *

Another option would be to have a specific JPA entity graph to handle this case.

+ */ +@RestController +@RequestMapping("/api") +public class UserResource { + + private final Logger log = LoggerFactory.getLogger(UserResource.class); + + private static final String ENTITY_NAME = "userManagement"; + + private final UserRepository userRepository; + + private final MailService mailService; + + private final UserService userService; + + public UserResource(UserRepository userRepository, MailService mailService, + UserService userService) { + + this.userRepository = userRepository; + this.mailService = mailService; + this.userService = userService; + } + + /** + * POST /users : Creates a new user. + *

+ * Creates a new user if the login and email are not already used, and sends an + * mail with an activation link. + * The user needs to be activated on creation. + *

+ * + * @param managedUserVM the user to create + * @return the ResponseEntity with status 201 (Created) and with body the new user, or with status 400 (Bad Request) if the login or email is already in use + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/users") + @Timed + @Secured(AuthoritiesConstants.ADMIN) + public ResponseEntity createUser(@RequestBody ManagedUserVM managedUserVM) throws URISyntaxException { + log.debug("REST request to save User : {}", managedUserVM); + + if (managedUserVM.getId() != null) { + return ResponseEntity.badRequest() + .headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new user cannot already have an ID")) + .body(null); + // Lowercase the user login before comparing with database + } else if (userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()).isPresent()) { + return ResponseEntity.badRequest() + .headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "userexists", "Login already in use")) + .body(null); + } else if (userRepository.findOneByEmail(managedUserVM.getEmail()).isPresent()) { + return ResponseEntity.badRequest() + .headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "emailexists", "Email already in use")) + .body(null); + } else { + User newUser = userService.createUser(managedUserVM); + mailService.sendCreationEmail(newUser); + return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin())) + .headers(HeaderUtil.createAlert( "userManagement.created", newUser.getLogin())) + .body(newUser); + } + } + + /** + * PUT /users : Updates an existing User. + * + * @param managedUserVM the user to update + * @return the ResponseEntity with status 200 (OK) and with body the updated user, + * or with status 400 (Bad Request) if the login or email is already in use, + * or with status 500 (Internal Server Error) if the user couldn't be updated + */ + @PutMapping("/users") + @Timed + @Secured(AuthoritiesConstants.ADMIN) + public ResponseEntity updateUser(@RequestBody ManagedUserVM managedUserVM) { + log.debug("REST request to update User : {}", managedUserVM); + Optional existingUser = userRepository.findOneByEmail(managedUserVM.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(managedUserVM.getId()))) { + return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "emailexists", "E-mail already in use")).body(null); + } + existingUser = userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()); + if (existingUser.isPresent() && (!existingUser.get().getId().equals(managedUserVM.getId()))) { + return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "userexists", "Login already in use")).body(null); + } + Optional updatedUser = userService.updateUser(managedUserVM); + + return ResponseUtil.wrapOrNotFound(updatedUser, + HeaderUtil.createAlert("userManagement.updated", managedUserVM.getLogin())); + } + + /** + * GET /users : get all users. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and with body all users + */ + @GetMapping("/users") + @Timed + public ResponseEntity> getAllUsers(@ApiParam Pageable pageable) { + final Page page = userService.getAllManagedUsers(pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"); + return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + } + + /** + * GET /users/:login : get the "login" user. + * + * @param login the login of the user to find + * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found) + */ + @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + @Timed + public ResponseEntity getUser(@PathVariable String login) { + log.debug("REST request to get User : {}", login); + return ResponseUtil.wrapOrNotFound( + userService.getUserWithAuthoritiesByLogin(login) + .map(UserDTO::new)); + } + + /** + * DELETE /users/:login : delete the "login" User. + * + * @param login the login of the user to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}") + @Timed + @Secured(AuthoritiesConstants.ADMIN) + public ResponseEntity deleteUser(@PathVariable String login) { + log.debug("REST request to delete User: {}", login); + userService.deleteUser(login); + return ResponseEntity.ok().headers(HeaderUtil.createAlert( "userManagement.deleted", login)).build(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/CustomParameterizedException.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/CustomParameterizedException.java new file mode 100644 index 0000000000..ab7754476b --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/CustomParameterizedException.java @@ -0,0 +1,34 @@ +package com.baeldung.web.rest.errors; + +/** + * Custom, parameterized exception, which can be translated on the client side. + * For example: + * + *
+ * throw new CustomParameterizedException("myCustomError", "hello", "world");
+ * 
+ * + * Can be translated with: + * + *
+ * "error.myCustomError" :  "The server says {{params[0]}} to {{params[1]}}"
+ * 
+ */ +public class CustomParameterizedException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final String message; + private final String[] params; + + public CustomParameterizedException(String message, String... params) { + super(message); + this.message = message; + this.params = params; + } + + public ParameterizedErrorVM getErrorVM() { + return new ParameterizedErrorVM(message, params); + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorConstants.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorConstants.java new file mode 100644 index 0000000000..69f21ed96c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorConstants.java @@ -0,0 +1,14 @@ +package com.baeldung.web.rest.errors; + +public final class ErrorConstants { + + public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; + public static final String ERR_ACCESS_DENIED = "error.accessDenied"; + public static final String ERR_VALIDATION = "error.validation"; + public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported"; + public static final String ERR_INTERNAL_SERVER_ERROR = "error.internalServerError"; + + private ErrorConstants() { + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorVM.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorVM.java new file mode 100644 index 0000000000..22fb066135 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/ErrorVM.java @@ -0,0 +1,52 @@ +package com.baeldung.web.rest.errors; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * View Model for transferring error message with a list of field errors. + */ +public class ErrorVM implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String message; + private final String description; + + private List fieldErrors; + + public ErrorVM(String message) { + this(message, null); + } + + public ErrorVM(String message, String description) { + this.message = message; + this.description = description; + } + + public ErrorVM(String message, String description, List fieldErrors) { + this.message = message; + this.description = description; + this.fieldErrors = fieldErrors; + } + + public void add(String objectName, String field, String message) { + if (fieldErrors == null) { + fieldErrors = new ArrayList<>(); + } + fieldErrors.add(new FieldErrorVM(objectName, field, message)); + } + + public String getMessage() { + return message; + } + + public String getDescription() { + return description; + } + + public List getFieldErrors() { + return fieldErrors; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/ExceptionTranslator.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/ExceptionTranslator.java new file mode 100644 index 0000000000..51925bfa61 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/ExceptionTranslator.java @@ -0,0 +1,85 @@ +package com.baeldung.web.rest.errors; + +import java.util.List; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.ResponseEntity.BodyBuilder; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.*; + +/** + * Controller advice to translate the server side exceptions to client-friendly json structures. + */ +@ControllerAdvice +public class ExceptionTranslator { + + @ExceptionHandler(ConcurrencyFailureException.class) + @ResponseStatus(HttpStatus.CONFLICT) + @ResponseBody + public ErrorVM processConcurrencyError(ConcurrencyFailureException ex) { + return new ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + public ErrorVM processValidationError(MethodArgumentNotValidException ex) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result.getFieldErrors(); + + return processFieldErrors(fieldErrors); + } + + @ExceptionHandler(CustomParameterizedException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + public ParameterizedErrorVM processParameterizedValidationError(CustomParameterizedException ex) { + return ex.getErrorVM(); + } + + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + @ResponseBody + public ErrorVM processAccessDeniedException(AccessDeniedException e) { + return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage()); + } + + private ErrorVM processFieldErrors(List fieldErrors) { + ErrorVM dto = new ErrorVM(ErrorConstants.ERR_VALIDATION); + + for (FieldError fieldError : fieldErrors) { + dto.add(fieldError.getObjectName(), fieldError.getField(), fieldError.getCode()); + } + + return dto; + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseBody + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public ErrorVM processMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) { + return new ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, exception.getMessage()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity processRuntimeException(Exception ex) { + BodyBuilder builder; + ErrorVM errorVM; + ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class); + if (responseStatus != null) { + builder = ResponseEntity.status(responseStatus.value()); + errorVM = new ErrorVM("error." + responseStatus.value().value(), responseStatus.reason()); + } else { + builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR); + errorVM = new ErrorVM(ErrorConstants.ERR_INTERNAL_SERVER_ERROR, "Internal server error"); + } + return builder.body(errorVM); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/FieldErrorVM.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/FieldErrorVM.java new file mode 100644 index 0000000000..19ab640ec7 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/FieldErrorVM.java @@ -0,0 +1,33 @@ +package com.baeldung.web.rest.errors; + +import java.io.Serializable; + +public class FieldErrorVM implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String objectName; + + private final String field; + + private final String message; + + public FieldErrorVM(String dto, String field, String message) { + this.objectName = dto; + this.field = field; + this.message = message; + } + + public String getObjectName() { + return objectName; + } + + public String getField() { + return field; + } + + public String getMessage() { + return message; + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/errors/ParameterizedErrorVM.java b/jhipster/src/main/java/com/baeldung/web/rest/errors/ParameterizedErrorVM.java new file mode 100644 index 0000000000..18500c51af --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/errors/ParameterizedErrorVM.java @@ -0,0 +1,27 @@ +package com.baeldung.web.rest.errors; + +import java.io.Serializable; + +/** + * View Model for sending a parameterized error message. + */ +public class ParameterizedErrorVM implements Serializable { + + private static final long serialVersionUID = 1L; + private final String message; + private final String[] params; + + public ParameterizedErrorVM(String message, String... params) { + this.message = message; + this.params = params; + } + + public String getMessage() { + return message; + } + + public String[] getParams() { + return params; + } + +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/package-info.java b/jhipster/src/main/java/com/baeldung/web/rest/package-info.java new file mode 100644 index 0000000000..0a74f6e90c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/package-info.java @@ -0,0 +1,4 @@ +/** + * Spring MVC REST controllers. + */ +package com.baeldung.web.rest; diff --git a/jhipster/src/main/java/com/baeldung/web/rest/util/HeaderUtil.java b/jhipster/src/main/java/com/baeldung/web/rest/util/HeaderUtil.java new file mode 100644 index 0000000000..7c643e9323 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/util/HeaderUtil.java @@ -0,0 +1,45 @@ +package com.baeldung.web.rest.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; + +/** + * Utility class for HTTP headers creation. + */ +public final class HeaderUtil { + + private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class); + + private static final String APPLICATION_NAME = "baeldungApp"; + + private HeaderUtil() { + } + + public static HttpHeaders createAlert(String message, String param) { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-baeldungApp-alert", message); + headers.add("X-baeldungApp-params", param); + return headers; + } + + public static HttpHeaders createEntityCreationAlert(String entityName, String param) { + return createAlert(APPLICATION_NAME + "." + entityName + ".created", param); + } + + public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { + return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param); + } + + public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { + return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param); + } + + public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) { + log.error("Entity creation failed, {}", defaultMessage); + HttpHeaders headers = new HttpHeaders(); + headers.add("X-baeldungApp-error", "error." + errorKey); + headers.add("X-baeldungApp-params", entityName); + return headers; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/util/PaginationUtil.java b/jhipster/src/main/java/com/baeldung/web/rest/util/PaginationUtil.java new file mode 100644 index 0000000000..affcb7842c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/util/PaginationUtil.java @@ -0,0 +1,47 @@ +package com.baeldung.web.rest.util; + +import org.springframework.data.domain.Page; +import org.springframework.http.HttpHeaders; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URISyntaxException; + +/** + * Utility class for handling pagination. + * + *

+ * Pagination uses the same principles as the Github API, + * and follow RFC 5988 (Link header). + */ +public final class PaginationUtil { + + private PaginationUtil() { + } + + public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) { + + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Total-Count", "" + Long.toString(page.getTotalElements())); + String link = ""; + if ((page.getNumber() + 1) < page.getTotalPages()) { + link = "<" + generateUri(baseUrl, page.getNumber() + 1, page.getSize()) + ">; rel=\"next\","; + } + // prev link + if ((page.getNumber()) > 0) { + link += "<" + generateUri(baseUrl, page.getNumber() - 1, page.getSize()) + ">; rel=\"prev\","; + } + // last and first link + int lastPage = 0; + if (page.getTotalPages() > 0) { + lastPage = page.getTotalPages() - 1; + } + link += "<" + generateUri(baseUrl, lastPage, page.getSize()) + ">; rel=\"last\","; + link += "<" + generateUri(baseUrl, 0, page.getSize()) + ">; rel=\"first\""; + headers.add(HttpHeaders.LINK, link); + return headers; + } + + private static String generateUri(String baseUrl, int page, int size) { + return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/vm/KeyAndPasswordVM.java b/jhipster/src/main/java/com/baeldung/web/rest/vm/KeyAndPasswordVM.java new file mode 100644 index 0000000000..94465f309f --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/vm/KeyAndPasswordVM.java @@ -0,0 +1,27 @@ +package com.baeldung.web.rest.vm; + +/** + * View Model object for storing the user's key and password. + */ +public class KeyAndPasswordVM { + + private String key; + + private String newPassword; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/vm/LoggerVM.java b/jhipster/src/main/java/com/baeldung/web/rest/vm/LoggerVM.java new file mode 100644 index 0000000000..56f77aec85 --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/vm/LoggerVM.java @@ -0,0 +1,48 @@ +package com.baeldung.web.rest.vm; + +import ch.qos.logback.classic.Logger; +import com.fasterxml.jackson.annotation.JsonCreator; + +/** + * View Model object for storing a Logback logger. + */ +public class LoggerVM { + + private String name; + + private String level; + + public LoggerVM(Logger logger) { + this.name = logger.getName(); + this.level = logger.getEffectiveLevel().toString(); + } + + @JsonCreator + public LoggerVM() { + // Empty public constructor used by Jackson. + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + @Override + public String toString() { + return "LoggerVM{" + + "name='" + name + '\'' + + ", level='" + level + '\'' + + '}'; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/vm/LoginVM.java b/jhipster/src/main/java/com/baeldung/web/rest/vm/LoginVM.java new file mode 100644 index 0000000000..a910d0d59c --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/vm/LoginVM.java @@ -0,0 +1,55 @@ +package com.baeldung.web.rest.vm; + +import com.baeldung.config.Constants; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +/** + * View Model object for storing a user's credentials. + */ +public class LoginVM { + + @Pattern(regexp = Constants.LOGIN_REGEX) + @NotNull + @Size(min = 1, max = 50) + private String username; + + @NotNull + @Size(min = ManagedUserVM.PASSWORD_MIN_LENGTH, max = ManagedUserVM.PASSWORD_MAX_LENGTH) + private String password; + + private Boolean rememberMe; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Boolean isRememberMe() { + return rememberMe; + } + + public void setRememberMe(Boolean rememberMe) { + this.rememberMe = rememberMe; + } + + @Override + public String toString() { + return "LoginVM{" + + "username='" + username + '\'' + + ", rememberMe=" + rememberMe + + '}'; + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/vm/ManagedUserVM.java b/jhipster/src/main/java/com/baeldung/web/rest/vm/ManagedUserVM.java new file mode 100644 index 0000000000..0899f0d0aa --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/vm/ManagedUserVM.java @@ -0,0 +1,45 @@ +package com.baeldung.web.rest.vm; + +import com.baeldung.service.dto.UserDTO; +import javax.validation.constraints.Size; + +import java.time.ZonedDateTime; +import java.util.Set; + +/** + * View Model extending the UserDTO, which is meant to be used in the user management UI. + */ +public class ManagedUserVM extends UserDTO { + + public static final int PASSWORD_MIN_LENGTH = 4; + + public static final int PASSWORD_MAX_LENGTH = 100; + + @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) + private String password; + + public ManagedUserVM() { + // Empty constructor needed for Jackson. + } + + public ManagedUserVM(Long id, String login, String password, String firstName, String lastName, + String email, boolean activated, String imageUrl, String langKey, + String createdBy, ZonedDateTime createdDate, String lastModifiedBy, ZonedDateTime lastModifiedDate, + Set authorities) { + + super(id, login, firstName, lastName, email, activated, imageUrl, langKey, + createdBy, createdDate, lastModifiedBy, lastModifiedDate, authorities); + + this.password = password; + } + + public String getPassword() { + return password; + } + + @Override + public String toString() { + return "ManagedUserVM{" + + "} " + super.toString(); + } +} diff --git a/jhipster/src/main/java/com/baeldung/web/rest/vm/package-info.java b/jhipster/src/main/java/com/baeldung/web/rest/vm/package-info.java new file mode 100644 index 0000000000..8d56157b6a --- /dev/null +++ b/jhipster/src/main/java/com/baeldung/web/rest/vm/package-info.java @@ -0,0 +1,4 @@ +/** + * View Models used by Spring MVC REST controllers. + */ +package com.baeldung.web.rest.vm; diff --git a/jhipster/src/main/resources/.h2.server.properties b/jhipster/src/main/resources/.h2.server.properties new file mode 100644 index 0000000000..f8b4429902 --- /dev/null +++ b/jhipster/src/main/resources/.h2.server.properties @@ -0,0 +1,5 @@ +#H2 Server Properties +0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./target/h2db/db/baeldung|baeldung +webAllowOthers=true +webPort=8082 +webSSL=false diff --git a/jhipster/src/main/resources/banner.txt b/jhipster/src/main/resources/banner.txt new file mode 100644 index 0000000000..c3d8cf725d --- /dev/null +++ b/jhipster/src/main/resources/banner.txt @@ -0,0 +1,10 @@ + + ${AnsiColor.GREEN} ██╗${AnsiColor.RED} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗ + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ██║ ██║ â•šâ•â•â–ˆâ–ˆâ•”â•â•â• ██╔â•â•â•â–ˆâ–ˆâ•— ██╔â•â•â•â•â• â•šâ•â•â–ˆâ–ˆâ•”â•â•â• ██╔â•â•â•â•â•â• ██╔â•â•â•â–ˆâ–ˆâ•— + ${AnsiColor.GREEN} ██║${AnsiColor.RED} ████████║ ██║ ███████╔╠╚█████╗ ██║ ██████╗ ███████╔╠+ ${AnsiColor.GREEN}██╗ ██║${AnsiColor.RED} ██╔â•â•â•â–ˆâ–ˆâ•‘ ██║ ██╔â•â•â•â•â• â•šâ•â•â•â–ˆâ–ˆâ•— ██║ ██╔â•â•â•â• ██╔â•â•â–ˆâ–ˆâ•‘ + ${AnsiColor.GREEN}╚██████╔â•${AnsiColor.RED} ██║ ██║ ████████╗ ██║ ██████╔╠██║ ████████╗ ██║ ╚██╗ + ${AnsiColor.GREEN} â•šâ•â•â•â•â•â• ${AnsiColor.RED} â•šâ•â• â•šâ•â• â•šâ•â•â•â•â•â•â•â• â•šâ•â• â•šâ•â•â•â•â•â• â•šâ•â• â•šâ•â•â•â•â•â•â•â• â•šâ•â• â•šâ•â• + +${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: +:: http://jhipster.github.io ::${AnsiColor.DEFAULT} diff --git a/jhipster/src/main/resources/config/application-dev.yml b/jhipster/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000000..d75c2549c8 --- /dev/null +++ b/jhipster/src/main/resources/config/application-dev.yml @@ -0,0 +1,130 @@ +# =================================================================== +# Spring Boot configuration for the "dev" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://jhipster.github.io/profiles/ +# More information on configuration properties: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +spring: + profiles: + active: dev + include: swagger + devtools: + restart: + enabled: true + livereload: + enabled: false # we use gulp + BrowserSync for livereload + jackson: + serialization.indent_output: true + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:file:./target/h2db/db/baeldung;DB_CLOSE_DELAY=-1 + username: baeldung + password: + h2: + console: + enabled: false + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + show-sql: true + properties: + hibernate.id.new_generator_mappings: true + hibernate.cache.use_second_level_cache: true + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + hibernate.cache.region.factory_class: io.github.jhipster.config.jcache.NoDefaultJCacheRegionFactory + mail: + host: localhost + port: 25 + username: + password: + messages: + cache-seconds: 1 + thymeleaf: + cache: false + +liquibase: + contexts: dev + +# =================================================================== +# To enable SSL, generate a certificate using: +# keytool -genkey -alias baeldung -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 +# +# You can also use Let's Encrypt: +# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm +# +# Then, modify the server.ssl properties so your "server" configuration looks like: +# +# server: +# port: 8443 +# ssl: +# key-store: keystore.p12 +# key-store-password: +# keyStoreType: PKCS12 +# keyAlias: baeldung +# =================================================================== +server: + port: 8080 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need SSL support (see above the "server.ssl" configuration) + cache: # Cache configuration + ehcache: # Ehcache configuration + time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache + max-entries: 100 # Number of objects in each cache entry + security: + authentication: + jwt: + secret: my-secret-token-to-change-in-production + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: baeldung@localhost + base-url: http://127.0.0.1:8080 + metrics: # DropWizard Metrics configuration, used by MetricsConfiguration + jmx.enabled: true + graphite: # Use the "graphite" Maven profile to have the Graphite dependencies + enabled: false + host: localhost + port: 2003 + prefix: baeldung + prometheus: # Use the "prometheus" Maven profile to have the Prometheus dependencies + enabled: false + endpoint: /prometheusMetrics + logs: # Reports Dropwizard metrics in the logs + enabled: false + reportFrequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://jhipster.github.io/common-application-properties/ +# =================================================================== + +application: diff --git a/jhipster/src/main/resources/config/application-prod.yml b/jhipster/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000000..a46fbd1c73 --- /dev/null +++ b/jhipster/src/main/resources/config/application-prod.yml @@ -0,0 +1,132 @@ +# =================================================================== +# Spring Boot configuration for the "prod" profile. +# +# This configuration overrides the application.yml file. +# +# More information on profiles: https://jhipster.github.io/profiles/ +# More information on configuration properties: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +spring: + devtools: + restart: + enabled: false + livereload: + enabled: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:mysql://localhost:3306/baeldung?useUnicode=true&characterEncoding=utf8&useSSL=false + username: root + password: + hikari: + data-source-properties: + cachePrepStmts: true + prepStmtCacheSize: 250 + prepStmtCacheSqlLimit: 2048 + useServerPrepStmts: true + jpa: + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: MYSQL + show-sql: false + properties: + hibernate.id.new_generator_mappings: true + hibernate.cache.use_second_level_cache: true + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: false + hibernate.cache.region.factory_class: io.github.jhipster.config.jcache.NoDefaultJCacheRegionFactory + mail: + host: localhost + port: 25 + username: + password: + thymeleaf: + cache: true + +liquibase: + contexts: prod + +# =================================================================== +# To enable SSL, generate a certificate using: +# keytool -genkey -alias baeldung -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 +# +# You can also use Let's Encrypt: +# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm +# +# Then, modify the server.ssl properties so your "server" configuration looks like: +# +# server: +# port: 443 +# ssl: +# key-store: keystore.p12 +# key-store-password: +# keyStoreType: PKCS12 +# keyAlias: baeldung +# =================================================================== +server: + port: 8080 + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css, application/javascript, application/json + min-response-size: 1024 + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +jhipster: + http: + version: V_1_1 # To use HTTP/2 you will need SSL support (see above the "server.ssl" configuration) + cache: # Used by the CachingHttpHeadersFilter + timeToLiveInDays: 1461 + cache: # Cache configuration + ehcache: # Ehcache configuration + time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache + max-entries: 1000 # Number of objects in each cache entry + security: + authentication: + jwt: + secret: e1d4b69d3f953e3fa622121e882e6f459ca20ca4 + # Token is valid 24 hours + token-validity-in-seconds: 86400 + token-validity-in-seconds-for-remember-me: 2592000 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: baeldung@localhost + base-url: http://my-server-url-to-change # Modify according to your server's URL + metrics: # DropWizard Metrics configuration, used by MetricsConfiguration + jmx.enabled: true + graphite: + enabled: false + host: localhost + port: 2003 + prefix: baeldung + prometheus: + enabled: false + endpoint: /prometheusMetrics + logs: # Reports Dropwizard metrics in the logs + enabled: false + reportFrequency: 60 # in seconds + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://jhipster.github.io/common-application-properties/ +# =================================================================== + +application: diff --git a/jhipster/src/main/resources/config/application.yml b/jhipster/src/main/resources/config/application.yml new file mode 100644 index 0000000000..ed48baf853 --- /dev/null +++ b/jhipster/src/main/resources/config/application.yml @@ -0,0 +1,106 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration will be overriden by the Spring profile you use, +# for example application-dev.yml if you use the "dev" profile. +# +# More information on profiles: https://jhipster.github.io/profiles/ +# More information on configuration properties: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +management: + security: + roles: ADMIN + context-path: /management + health: + mail: + enabled: false # When using the MailService, configure an SMTP server and set this to true +spring: + application: + name: baeldung + profiles: + # The commented value for `active` can be replaced with valid Spring profiles to load. + # Otherwise, it will be filled in by maven when building the WAR file + # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` + active: #spring.profiles.active# + jackson: + serialization.write_dates_as_timestamps: false + jpa: + open-in-view: false + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: XHTML + +security: + basic: + enabled: false + +server: + session: + cookie: + http-only: true + +info: + project: + version: #project.version# + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 2 + max-pool-size: 50 + queue-capacity: 10000 + # By default CORS is disabled. Uncomment to enable. + #cors: + #allowed-origins: "*" + #allowed-methods: GET, PUT, POST, DELETE, OPTIONS + #allowed-headers: "*" + #exposed-headers: + #allow-credentials: true + #max-age: 1800 + mail: + from: baeldung@localhost + swagger: + default-include-pattern: /api/.* + title: baeldung API + description: baeldung API documentation + version: 0.0.1 + terms-of-service-url: + contact-name: + contact-url: + contact-email: + license: + license-url: + ribbon: + display-on-active-profiles: dev + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://jhipster.github.io/common-application-properties/ +# =================================================================== + +application: diff --git a/jhipster/src/main/resources/config/liquibase/authorities.csv b/jhipster/src/main/resources/config/liquibase/authorities.csv new file mode 100644 index 0000000000..af5c6dfa18 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/authorities.csv @@ -0,0 +1,3 @@ +name +ROLE_ADMIN +ROLE_USER diff --git a/jhipster/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/jhipster/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml new file mode 100644 index 0000000000..98ac548808 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_Post.xml b/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_Post.xml new file mode 100644 index 0000000000..ce4773262c --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_Post.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_constraints_Post.xml b/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_constraints_Post.xml new file mode 100644 index 0000000000..2040980371 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/changelog/20170316223211_added_entity_constraints_Post.xml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_Comment.xml b/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_Comment.xml new file mode 100644 index 0000000000..d0b26503e1 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_Comment.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_constraints_Comment.xml b/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_constraints_Comment.xml new file mode 100644 index 0000000000..b7670e747c --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/changelog/20170316224021_added_entity_constraints_Comment.xml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/master.xml b/jhipster/src/main/resources/config/liquibase/master.xml new file mode 100644 index 0000000000..32eb479989 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/master.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/jhipster/src/main/resources/config/liquibase/users.csv b/jhipster/src/main/resources/config/liquibase/users.csv new file mode 100644 index 0000000000..b25922b699 --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/users.csv @@ -0,0 +1,5 @@ +id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;system;$2a$10$mE.qmcV0mFU5NcKh73TZx.z4ueI/.bDWbj0T1BYyqP481kGGarKLG;System;System;system@localhost;;true;en;system;system +2;anonymoususer;$2a$10$j8S5d7Sr7.8VTOYNviDPOeWX8KcYILUVJBsYV83Y5NtECayypx9lO;Anonymous;User;anonymous@localhost;;true;en;system;system +3;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +4;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system diff --git a/jhipster/src/main/resources/config/liquibase/users_authorities.csv b/jhipster/src/main/resources/config/liquibase/users_authorities.csv new file mode 100644 index 0000000000..06c5feeeea --- /dev/null +++ b/jhipster/src/main/resources/config/liquibase/users_authorities.csv @@ -0,0 +1,6 @@ +user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +3;ROLE_ADMIN +3;ROLE_USER +4;ROLE_USER diff --git a/jhipster/src/main/resources/i18n/messages.properties b/jhipster/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000000..1c28002acd --- /dev/null +++ b/jhipster/src/main/resources/i18n/messages.properties @@ -0,0 +1,22 @@ +# Error page +error.title=Your request cannot be processed +error.subtitle=Sorry, an error has occurred. +error.status=Status: +error.message=Message: + +# Activation e-mail +email.activation.title=baeldung account activation +email.activation.greeting=Dear {0} +email.activation.text1=Your baeldung account has been created, please click on the URL below to activate it: +email.activation.text2=Regards, +email.signature=baeldung Team. + +# Creation email +email.creation.text1=Your baeldung account has been created, please click on the URL below to access it: + +# Reset e-mail +email.reset.title=baeldung password reset +email.reset.greeting=Dear {0} +email.reset.text1=For your baeldung account a password reset was requested, please click on the URL below to reset it: +email.reset.text2=Regards, + diff --git a/jhipster/src/main/resources/i18n/messages_en.properties b/jhipster/src/main/resources/i18n/messages_en.properties new file mode 100644 index 0000000000..1c28002acd --- /dev/null +++ b/jhipster/src/main/resources/i18n/messages_en.properties @@ -0,0 +1,22 @@ +# Error page +error.title=Your request cannot be processed +error.subtitle=Sorry, an error has occurred. +error.status=Status: +error.message=Message: + +# Activation e-mail +email.activation.title=baeldung account activation +email.activation.greeting=Dear {0} +email.activation.text1=Your baeldung account has been created, please click on the URL below to activate it: +email.activation.text2=Regards, +email.signature=baeldung Team. + +# Creation email +email.creation.text1=Your baeldung account has been created, please click on the URL below to access it: + +# Reset e-mail +email.reset.title=baeldung password reset +email.reset.greeting=Dear {0} +email.reset.text1=For your baeldung account a password reset was requested, please click on the URL below to reset it: +email.reset.text2=Regards, + diff --git a/jhipster/src/main/resources/logback-spring.xml b/jhipster/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000..3c62a70c31 --- /dev/null +++ b/jhipster/src/main/resources/logback-spring.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + diff --git a/jhipster/src/main/resources/mails/activationEmail.html b/jhipster/src/main/resources/mails/activationEmail.html new file mode 100644 index 0000000000..9fb22a7796 --- /dev/null +++ b/jhipster/src/main/resources/mails/activationEmail.html @@ -0,0 +1,24 @@ + + + + JHipster activation + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to activate it: +

+

+ Activation Link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster/src/main/resources/mails/creationEmail.html b/jhipster/src/main/resources/mails/creationEmail.html new file mode 100644 index 0000000000..a59d91da0c --- /dev/null +++ b/jhipster/src/main/resources/mails/creationEmail.html @@ -0,0 +1,24 @@ + + + + JHipster creation + + + +

+ Dear +

+

+ Your JHipster account has been created, please click on the URL below to access it: +

+

+ login +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster/src/main/resources/mails/passwordResetEmail.html b/jhipster/src/main/resources/mails/passwordResetEmail.html new file mode 100644 index 0000000000..30d5f62c60 --- /dev/null +++ b/jhipster/src/main/resources/mails/passwordResetEmail.html @@ -0,0 +1,24 @@ + + + + JHipster password reset + + + +

+ Dear +

+

+ For your JHipster account a password reset was requested, please click on the URL below to reset it: +

+

+ Reset Link +

+

+ Regards, +
+ JHipster. +

+ + diff --git a/jhipster/src/main/resources/templates/error.html b/jhipster/src/main/resources/templates/error.html new file mode 100644 index 0000000000..774b080d6c --- /dev/null +++ b/jhipster/src/main/resources/templates/error.html @@ -0,0 +1,162 @@ + + + + + Your request cannot be processed + + + +
+

Your request cannot be processed :(

+ +

Sorry, an error has occurred.

+ + Status:  ()
+ + Message: 
+
+ + + +
+ + diff --git a/jhipster/src/main/webapp/404.html b/jhipster/src/main/webapp/404.html new file mode 100644 index 0000000000..8d7925a892 --- /dev/null +++ b/jhipster/src/main/webapp/404.html @@ -0,0 +1,60 @@ + + + + + Page Not Found + + + + +

Page Not Found

+

Sorry, but the page you were trying to view does not exist.

+ + + diff --git a/jhipster/src/main/webapp/app/account/account.module.ts b/jhipster/src/main/webapp/app/account/account.module.ts new file mode 100644 index 0000000000..09b19a7555 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/account.module.ts @@ -0,0 +1,45 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BaeldungSharedModule } from '../shared'; + +import { + Register, + Activate, + Password, + PasswordResetInit, + PasswordResetFinish, + PasswordStrengthBarComponent, + RegisterComponent, + ActivateComponent, + PasswordComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent, + accountState +} from './'; + +@NgModule({ + imports: [ + BaeldungSharedModule, + RouterModule.forRoot(accountState, { useHash: true }) + ], + declarations: [ + ActivateComponent, + RegisterComponent, + PasswordComponent, + PasswordStrengthBarComponent, + PasswordResetInitComponent, + PasswordResetFinishComponent, + SettingsComponent + ], + providers: [ + Register, + Activate, + Password, + PasswordResetInit, + PasswordResetFinish + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungAccountModule {} diff --git a/jhipster/src/main/webapp/app/account/account.route.ts b/jhipster/src/main/webapp/app/account/account.route.ts new file mode 100644 index 0000000000..4715216cf3 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/account.route.ts @@ -0,0 +1,26 @@ +import { Routes, CanActivate } from '@angular/router'; + +import { UserRouteAccessService } from '../shared'; + +import { + activateRoute, + passwordRoute, + passwordResetFinishRoute, + passwordResetInitRoute, + registerRoute, + settingsRoute +} from './'; + +let ACCOUNT_ROUTES = [ + activateRoute, + passwordRoute, + passwordResetFinishRoute, + passwordResetInitRoute, + registerRoute, + settingsRoute +]; + +export const accountState: Routes = [{ + path: '', + children: ACCOUNT_ROUTES +}]; diff --git a/jhipster/src/main/webapp/app/account/activate/activate.component.html b/jhipster/src/main/webapp/app/account/activate/activate.component.html new file mode 100644 index 0000000000..25e3f23417 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/activate/activate.component.html @@ -0,0 +1,19 @@ +
+
+
+

Activation

+ +
+ + Your user has been activated. Please + sign in. + +
+ +
+ Your user could not be activated. Please use the registration form to sign up. +
+ +
+
+
diff --git a/jhipster/src/main/webapp/app/account/activate/activate.component.ts b/jhipster/src/main/webapp/app/account/activate/activate.component.ts new file mode 100644 index 0000000000..dbaaa7d676 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/activate/activate.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Activate } from './activate.service'; +import { LoginModalService } from '../../shared'; + +@Component({ + selector: 'jhi-activate', + templateUrl: './activate.component.html' +}) +export class ActivateComponent implements OnInit { + error: string; + success: string; + modalRef: NgbModalRef; + + constructor( + private jhiLanguageService: JhiLanguageService, + private activate: Activate, + private loginModalService: LoginModalService, + private route: ActivatedRoute + ) { + this.jhiLanguageService.setLocations(['activate']); + } + + ngOnInit () { + this.route.queryParams.subscribe(params => { + this.activate.get(params['key']).subscribe(() => { + this.error = null; + this.success = 'OK'; + }, () => { + this.success = null; + this.error = 'ERROR'; + }); + }); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster/src/main/webapp/app/account/activate/activate.route.ts b/jhipster/src/main/webapp/app/account/activate/activate.route.ts new file mode 100644 index 0000000000..8f1bb32b58 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/activate/activate.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { ActivateComponent } from './activate.component'; + +export const activateRoute: Route = { + path: 'activate', + component: ActivateComponent, + data: { + authorities: [], + pageTitle: 'activate.title' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/account/activate/activate.service.ts b/jhipster/src/main/webapp/app/account/activate/activate.service.ts new file mode 100644 index 0000000000..f877a4d50e --- /dev/null +++ b/jhipster/src/main/webapp/app/account/activate/activate.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, URLSearchParams } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class Activate { + + constructor (private http: Http) {} + + get(key: string): Observable { + let params: URLSearchParams = new URLSearchParams(); + params.set('key', key); + + return this.http.get('api/activate', { + search: params + }).map((res: Response) => res); + } +} diff --git a/jhipster/src/main/webapp/app/account/index.ts b/jhipster/src/main/webapp/app/account/index.ts new file mode 100644 index 0000000000..aeada0551c --- /dev/null +++ b/jhipster/src/main/webapp/app/account/index.ts @@ -0,0 +1,19 @@ +export * from './activate/activate.component'; +export * from './activate/activate.service'; +export * from './activate/activate.route'; +export * from './password/password.component'; +export * from './password/password-strength-bar.component'; +export * from './password/password.service'; +export * from './password/password.route'; +export * from './password-reset/finish/password-reset-finish.component'; +export * from './password-reset/finish/password-reset-finish.service'; +export * from './password-reset/finish/password-reset-finish.route'; +export * from './password-reset/init/password-reset-init.component'; +export * from './password-reset/init/password-reset-init.service'; +export * from './password-reset/init/password-reset-init.route'; +export * from './register/register.component'; +export * from './register/register.service'; +export * from './register/register.route'; +export * from './settings/settings.component'; +export * from './settings/settings.route'; +export * from './account.route'; diff --git a/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html new file mode 100644 index 0000000000..a1dfde055c --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.html @@ -0,0 +1,77 @@ +
+
+
+

Reset password

+ +
+ The password reset key is missing. +
+ +
+

Choose a new password

+
+ +
+

Your password couldn't be reset. Remember a password request is only valid for 24 hours.

+
+ +

+ Your password has been reset. Please + sign in. +

+ +
+ The password and its confirmation do not match! +
+ +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+ +
+ + +
+ + Your password confirmation is required. + + + Your password confirmation is required to be at least 4 characters. + + + Your password confirmation cannot be longer than 50 characters. + +
+
+ +
+
+ +
+
+
diff --git a/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts new file mode 100644 index 0000000000..f1889920bd --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { ActivatedRoute } from '@angular/router'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { PasswordResetFinish } from './password-reset-finish.service'; +import { LoginModalService } from '../../../shared'; + +@Component({ + selector: 'jhi-password-reset-finish', + templateUrl: './password-reset-finish.component.html' +}) +export class PasswordResetFinishComponent implements OnInit, AfterViewInit { + confirmPassword: string; + doNotMatch: string; + error: string; + keyMissing: boolean; + resetAccount: any; + success: string; + modalRef: NgbModalRef; + key: string; + + constructor( + private jhiLanguageService: JhiLanguageService, + private passwordResetFinish: PasswordResetFinish, + private loginModalService: LoginModalService, + private route: ActivatedRoute, + private elementRef: ElementRef, private renderer: Renderer + ) { + this.jhiLanguageService.setLocations(['reset']); + } + + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.key = params['key']; + }); + this.resetAccount = {}; + this.keyMissing = !this.key; + } + + ngAfterViewInit() { + if (this.elementRef.nativeElement.querySelector('#password') != null) { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#password'), 'focus', []); + } + } + + finishReset() { + this.doNotMatch = null; + this.error = null; + if (this.resetAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.passwordResetFinish.save({key: this.key, newPassword: this.resetAccount.password}).subscribe(() => { + this.success = 'OK'; + }, () => { + this.success = null; + this.error = 'ERROR'; + }); + } + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts new file mode 100644 index 0000000000..7b02653ed5 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../../shared'; +import { PasswordResetFinishComponent } from './password-reset-finish.component'; + +export const passwordResetFinishRoute: Route = { + path: 'reset/finish', + component: PasswordResetFinishComponent, + data: { + authorities: [], + pageTitle: 'global.menu.account.password' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts new file mode 100644 index 0000000000..abd81374b0 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/finish/password-reset-finish.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class PasswordResetFinish { + + constructor (private http: Http) {} + + save(keyAndPassword: any): Observable { + return this.http.post('api/account/reset_password/finish', keyAndPassword); + } +} diff --git a/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html new file mode 100644 index 0000000000..2503433275 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.html @@ -0,0 +1,47 @@ +
+
+
+

Reset your password

+ +
+ E-Mail address isn't registered! Please check and try again. +
+ +
+

Enter the e-mail address you used to register.

+
+ +
+

Check your e-mails for details on how to reset your password.

+
+ +
+
+ + +
+ + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + +
+
+ +
+ +
+
+
diff --git a/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts new file mode 100644 index 0000000000..eba521dc05 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { PasswordResetInit } from './password-reset-init.service'; + +@Component({ + selector: 'jhi-password-reset-init', + templateUrl: './password-reset-init.component.html' +}) +export class PasswordResetInitComponent implements OnInit, AfterViewInit { + error: string; + errorEmailNotExists: string; + resetAccount: any; + success: string; + + constructor( + private jhiLanguageService: JhiLanguageService, + private passwordResetInit: PasswordResetInit, + private elementRef: ElementRef, + private renderer: Renderer + ) { + this.jhiLanguageService.setLocations(['reset']); + } + + ngOnInit() { + this.resetAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#email'), 'focus', []); + } + + requestReset () { + + this.error = null; + this.errorEmailNotExists = null; + + this.passwordResetInit.save(this.resetAccount.email).subscribe(() => { + this.success = 'OK'; + }, (response) => { + this.success = null; + if (response.status === 400 && response.data === 'e-mail address not registered') { + this.errorEmailNotExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + }); + } +} diff --git a/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts new file mode 100644 index 0000000000..37f7e8102d --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../../shared'; +import { PasswordResetInitComponent } from './password-reset-init.component'; + +export const passwordResetInitRoute: Route = { + path: 'reset/request', + component: PasswordResetInitComponent, + data: { + authorities: [], + pageTitle: 'global.menu.account.password' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts new file mode 100644 index 0000000000..fa466cd6cc --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password-reset/init/password-reset-init.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class PasswordResetInit { + + constructor (private http: Http) {} + + save(mail: string): Observable { + return this.http.post('api/account/reset_password/init', mail); + } +} diff --git a/jhipster/src/main/webapp/app/account/password/password-strength-bar.component.ts b/jhipster/src/main/webapp/app/account/password/password-strength-bar.component.ts new file mode 100644 index 0000000000..2a61d133d6 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password-strength-bar.component.ts @@ -0,0 +1,89 @@ +import { Component, ElementRef, Input, Renderer } from '@angular/core'; + +@Component({ + selector: 'jhi-password-strength-bar', + template: ` +
+ Password strength: +
    +
  • +
  • +
  • +
  • +
  • +
+
`, + styleUrls: [ + 'password-strength-bar.scss' + ] +}) +export class PasswordStrengthBarComponent { + + colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0']; + + constructor(private renderer: Renderer, private elementRef: ElementRef) { } + + measureStrength(p: string): number { + + let force = 0; + let regex = /[$-/:-?{-~!"^_`\[\]]/g; // " + + let lowerLetters = /[a-z]+/.test(p); + let upperLetters = /[A-Z]+/.test(p); + let numbers = /[0-9]+/.test(p); + let symbols = regex.test(p); + + let flags = [lowerLetters, upperLetters, numbers, symbols]; + let passedMatches = flags.filter( (isMatchedFlag: boolean) => { + return isMatchedFlag === true; + }).length; + + force += 2 * p.length + ((p.length >= 10) ? 1 : 0); + force += passedMatches * 10; + + // penality (short password) + force = (p.length <= 6) ? Math.min(force, 10) : force; + + // penality (poor variety of characters) + force = (passedMatches === 1) ? Math.min(force, 10) : force; + force = (passedMatches === 2) ? Math.min(force, 20) : force; + force = (passedMatches === 3) ? Math.min(force, 40) : force; + + return force; + }; + + getColor(s: number): any { + let idx = 0; + if (s <= 10) { + idx = 0; + } else if (s <= 20) { + idx = 1; + } else if (s <= 30) { + idx = 2; + } else if (s <= 40) { + idx = 3; + } else { + idx = 4; + } + return {idx: idx + 1, col: this.colors[idx]}; + }; + + @Input() + set passwordToCheck(password: string) { + if (password) { + let c = this.getColor(this.measureStrength(password)); + let element = this.elementRef.nativeElement; + if ( element.className ) { + this.renderer.setElementClass(element, element.className , false); + } + let lis = element.getElementsByTagName('li'); + for (let i = 0; i < lis.length; i++) { + if (i < c.idx) { + this.renderer.setElementStyle(lis[i], 'backgroundColor', c.col); + } else { + this.renderer.setElementStyle(lis[i], 'backgroundColor', '#DDD'); + } + } + } + } +} diff --git a/jhipster/src/main/webapp/app/account/password/password-strength-bar.scss b/jhipster/src/main/webapp/app/account/password/password-strength-bar.scss new file mode 100644 index 0000000000..8f8effcb60 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password-strength-bar.scss @@ -0,0 +1,23 @@ +/* ========================================================================== +start Password strength bar style +========================================================================== */ +ul#strength { + display:inline; + list-style:none; + margin:0; + margin-left:15px; + padding:0; + vertical-align:2px; +} + +.point { + background:#DDD; + border-radius:2px; + display:inline-block; + height:5px; + margin-right:1px; + width:20px; + &:last { + margin:0 !important; + } +} diff --git a/jhipster/src/main/webapp/app/account/password/password.component.html b/jhipster/src/main/webapp/app/account/password/password.component.html new file mode 100644 index 0000000000..2534bccdfc --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password.component.html @@ -0,0 +1,65 @@ +
+
+
+

Password for [{{account.login}}]

+ +
+ Password changed! +
+
+ An error has occurred! The password could not be changed. +
+ +
+ The password and its confirmation do not match! +
+ +
+ +
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+
+
+
diff --git a/jhipster/src/main/webapp/app/account/password/password.component.ts b/jhipster/src/main/webapp/app/account/password/password.component.ts new file mode 100644 index 0000000000..f34eae423c --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Principal } from '../../shared'; +import { Password } from './password.service'; + +@Component({ + selector: 'jhi-password', + templateUrl: './password.component.html' +}) +export class PasswordComponent implements OnInit { + doNotMatch: string; + error: string; + success: string; + account: any; + password: string; + confirmPassword: string; + + constructor( + private jhiLanguageService: JhiLanguageService, + private passwordService: Password, + private principal: Principal + ) { + this.jhiLanguageService.setLocations(['password']); + } + + ngOnInit () { + this.principal.identity().then((account) => { + this.account = account; + }); + } + + changePassword () { + if (this.password !== this.confirmPassword) { + this.error = null; + this.success = null; + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.passwordService.save(this.password).subscribe(() => { + this.error = null; + this.success = 'OK'; + }, () => { + this.success = null; + this.error = 'ERROR'; + }); + } + } +} diff --git a/jhipster/src/main/webapp/app/account/password/password.route.ts b/jhipster/src/main/webapp/app/account/password/password.route.ts new file mode 100644 index 0000000000..d5a7118458 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { PasswordComponent } from './password.component'; + +export const passwordRoute: Route = { + path: 'password', + component: PasswordComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'global.menu.account.password' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/account/password/password.service.ts b/jhipster/src/main/webapp/app/account/password/password.service.ts new file mode 100644 index 0000000000..0c220d8816 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/password/password.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class Password { + + constructor (private http: Http) {} + + save(newPassword: string): Observable { + return this.http.post('api/account/change_password', newPassword); + } +} diff --git a/jhipster/src/main/webapp/app/account/register/register.component.html b/jhipster/src/main/webapp/app/account/register/register.component.html new file mode 100644 index 0000000000..14a0c851e2 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/register/register.component.html @@ -0,0 +1,122 @@ +
+
+
+

Registration

+ +
+ Registration saved! Please check your email for confirmation. +
+ +
+ Registration failed! Please try again later. +
+ +
+ Login name already registered! Please choose another one. +
+ +
+ E-mail is already in use! Please choose another one. +
+ +
+ The password and its confirmation do not match! +
+
+
+
+
+ + +
+ + Your username is required. + + + Your username is required to be at least 1 character. + + + Your username cannot be longer than 50 characters. + + + Your username can only contain lower-case letters and digits. + +
+
+
+ + +
+ + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + +
+
+
+ + +
+ + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + +
+ +
+
+ + +
+ + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + +
+
+ + +
+

+
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+
+
+
diff --git a/jhipster/src/main/webapp/app/account/register/register.component.ts b/jhipster/src/main/webapp/app/account/register/register.component.ts new file mode 100644 index 0000000000..dc5c4ef2f4 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/register/register.component.ts @@ -0,0 +1,73 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Register } from './register.service'; +import { LoginModalService } from '../../shared'; + +@Component({ + selector: 'jhi-register', + templateUrl: './register.component.html' +}) +export class RegisterComponent implements OnInit, AfterViewInit { + + confirmPassword: string; + doNotMatch: string; + error: string; + errorEmailExists: string; + errorUserExists: string; + registerAccount: any; + success: boolean; + modalRef: NgbModalRef; + + constructor( + private languageService: JhiLanguageService, + private loginModalService: LoginModalService, + private registerService: Register, + private elementRef: ElementRef, + private renderer: Renderer + ) { + this.languageService.setLocations(['register']); + } + + ngOnInit() { + this.success = false; + this.registerAccount = {}; + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#login'), 'focus', []); + } + + register() { + if (this.registerAccount.password !== this.confirmPassword) { + this.doNotMatch = 'ERROR'; + } else { + this.doNotMatch = null; + this.error = null; + this.errorUserExists = null; + this.errorEmailExists = null; + this.languageService.getCurrent().then(key => { + this.registerAccount.langKey = key; + this.registerService.save(this.registerAccount).subscribe(() => { + this.success = true; + }, (response) => this.processError(response)); + }); + } + } + + openLogin() { + this.modalRef = this.loginModalService.open(); + } + + private processError(response) { + this.success = null; + if (response.status === 400 && response._body === 'login already in use') { + this.errorUserExists = 'ERROR'; + } else if (response.status === 400 && response._body === 'e-mail address already in use') { + this.errorEmailExists = 'ERROR'; + } else { + this.error = 'ERROR'; + } + } +} diff --git a/jhipster/src/main/webapp/app/account/register/register.route.ts b/jhipster/src/main/webapp/app/account/register/register.route.ts new file mode 100644 index 0000000000..3dc47f1e58 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/register/register.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { RegisterComponent } from './register.component'; + +export const registerRoute: Route = { + path: 'register', + component: RegisterComponent, + data: { + authorities: [], + pageTitle: 'register.title' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/account/register/register.service.ts b/jhipster/src/main/webapp/app/account/register/register.service.ts new file mode 100644 index 0000000000..87bbe9d37b --- /dev/null +++ b/jhipster/src/main/webapp/app/account/register/register.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class Register { + + constructor (private http: Http) {} + + save(account: any): Observable { + return this.http.post('api/register', account); + } +} diff --git a/jhipster/src/main/webapp/app/account/settings/settings.component.html b/jhipster/src/main/webapp/app/account/settings/settings.component.html new file mode 100644 index 0000000000..82fca9e804 --- /dev/null +++ b/jhipster/src/main/webapp/app/account/settings/settings.component.html @@ -0,0 +1,86 @@ +
+
+
+

User settings for [{{settingsAccount.login}}]

+ +
+ Settings saved! +
+ + + +
+ +
+ + +
+ + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + +
+
+
+ + +
+ + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + +
+
+
+ + +
+ +
+
+
+ +
diff --git a/jhipster/src/main/webapp/app/account/settings/settings.component.ts b/jhipster/src/main/webapp/app/account/settings/settings.component.ts new file mode 100644 index 0000000000..37f4c70e3b --- /dev/null +++ b/jhipster/src/main/webapp/app/account/settings/settings.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Principal, AccountService, JhiLanguageHelper } from '../../shared'; + +@Component({ + selector: 'jhi-settings', + templateUrl: './settings.component.html' +}) +export class SettingsComponent implements OnInit { + error: string; + success: string; + settingsAccount: any; + languages: any[]; + + constructor( + private account: AccountService, + private principal: Principal, + private languageService: JhiLanguageService, + private languageHelper: JhiLanguageHelper + ) { + this.languageService.setLocations(['settings']); + } + + ngOnInit () { + this.principal.identity().then((account) => { + this.settingsAccount = this.copyAccount(account); + }); + this.languageHelper.getAll().then((languages) => { + this.languages = languages; + }); + } + + save () { + this.account.save(this.settingsAccount).subscribe(() => { + this.error = null; + this.success = 'OK'; + this.principal.identity(true).then((account) => { + this.settingsAccount = this.copyAccount(account); + }); + this.languageService.getCurrent().then((current) => { + if (this.settingsAccount.langKey !== current) { + this.languageService.changeLanguage(this.settingsAccount.langKey); + } + }); + }, () => { + this.success = null; + this.error = 'ERROR'; + }); + } + + copyAccount (account) { + return { + activated: account.activated, + email: account.email, + firstName: account.firstName, + langKey: account.langKey, + lastName: account.lastName, + login: account.login, + imageUrl: account.imageUrl + }; + } +} diff --git a/jhipster/src/main/webapp/app/account/settings/settings.route.ts b/jhipster/src/main/webapp/app/account/settings/settings.route.ts new file mode 100644 index 0000000000..9c9a852c7b --- /dev/null +++ b/jhipster/src/main/webapp/app/account/settings/settings.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { SettingsComponent } from './settings.component'; + +export const settingsRoute: Route = { + path: 'settings', + component: SettingsComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'global.menu.account.settings' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/admin/admin.module.ts b/jhipster/src/main/webapp/app/admin/admin.module.ts new file mode 100644 index 0000000000..4ac749bc78 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/admin.module.ts @@ -0,0 +1,73 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { ParseLinks } from 'ng-jhipster'; + +import { BaeldungSharedModule } from '../shared'; + +import { + adminState, + AuditsComponent, + UserMgmtComponent, + UserDialogComponent, + UserDeleteDialogComponent, + UserMgmtDetailComponent, + UserMgmtDialogComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiMetricsMonitoringModalComponent, + JhiMetricsMonitoringComponent, + JhiHealthModalComponent, + JhiHealthCheckComponent, + JhiConfigurationComponent, + JhiDocsComponent, + AuditsService, + JhiConfigurationService, + JhiHealthService, + JhiMetricsService, + LogsService, + UserResolvePagingParams, + UserResolve, + UserModalService +} from './'; + + +@NgModule({ + imports: [ + BaeldungSharedModule, + RouterModule.forRoot(adminState, { useHash: true }) + ], + declarations: [ + AuditsComponent, + UserMgmtComponent, + UserDialogComponent, + UserDeleteDialogComponent, + UserMgmtDetailComponent, + UserMgmtDialogComponent, + UserMgmtDeleteDialogComponent, + LogsComponent, + JhiConfigurationComponent, + JhiHealthCheckComponent, + JhiHealthModalComponent, + JhiDocsComponent, + JhiMetricsMonitoringComponent, + JhiMetricsMonitoringModalComponent + ], + entryComponents: [ + UserMgmtDialogComponent, + UserMgmtDeleteDialogComponent, + JhiHealthModalComponent, + JhiMetricsMonitoringModalComponent, + ], + providers: [ + AuditsService, + JhiConfigurationService, + JhiHealthService, + JhiMetricsService, + LogsService, + UserResolvePagingParams, + UserResolve, + UserModalService + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungAdminModule {} diff --git a/jhipster/src/main/webapp/app/admin/admin.route.ts b/jhipster/src/main/webapp/app/admin/admin.route.ts new file mode 100644 index 0000000000..8e64d2d5c0 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/admin.route.ts @@ -0,0 +1,36 @@ +import { Routes, CanActivate } from '@angular/router'; + +import { + auditsRoute, + configurationRoute, + docsRoute, + healthRoute, + logsRoute, + metricsRoute, + userMgmtRoute, + userDialogRoute +} from './'; + +import { UserRouteAccessService } from '../shared'; + +let ADMIN_ROUTES = [ + auditsRoute, + configurationRoute, + docsRoute, + healthRoute, + logsRoute, + ...userMgmtRoute, + metricsRoute +]; + + +export const adminState: Routes = [{ + path: '', + data: { + authorities: ['ROLE_ADMIN'] + }, + canActivate: [UserRouteAccessService], + children: ADMIN_ROUTES +}, + ...userDialogRoute +]; diff --git a/jhipster/src/main/webapp/app/admin/audits/audit-data.model.ts b/jhipster/src/main/webapp/app/admin/audits/audit-data.model.ts new file mode 100644 index 0000000000..55a5e9c819 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audit-data.model.ts @@ -0,0 +1,6 @@ +export class AuditData { + constructor( + public remoteAddress: string, + public sessionId: string + ) { } +} diff --git a/jhipster/src/main/webapp/app/admin/audits/audit.model.ts b/jhipster/src/main/webapp/app/admin/audits/audit.model.ts new file mode 100644 index 0000000000..9ca753795c --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audit.model.ts @@ -0,0 +1,10 @@ +import { AuditData } from './audit-data.model'; + +export class Audit { + constructor( + public data: AuditData, + public principal: string, + public timestamp: string, + public type: string + ) { } +} diff --git a/jhipster/src/main/webapp/app/admin/audits/audits.component.html b/jhipster/src/main/webapp/app/admin/audits/audits.component.html new file mode 100644 index 0000000000..9fcbaf7ecd --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audits.component.html @@ -0,0 +1,45 @@ +
+

Audits

+ +
+
+

Filter by date

+

+ from + + to + +

+
+
+ +
+ + + + + + + + + + + + + + + +
DateUserStateExtra data
{{audit.timestamp| date:'medium'}}{{audit.principal}}{{audit.type}} + {{audit.data.message}} + Remote Address {{audit.data.remoteAddress}} +
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster/src/main/webapp/app/admin/audits/audits.component.ts b/jhipster/src/main/webapp/app/admin/audits/audits.component.ts new file mode 100644 index 0000000000..84e6b40fe8 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audits.component.ts @@ -0,0 +1,99 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import { DatePipe } from '@angular/common'; +import { ParseLinks, JhiLanguageService} from 'ng-jhipster'; + +import { Audit } from './audit.model'; +import { AuditsService } from './audits.service'; +import { ITEMS_PER_PAGE } from '../../shared'; +import { PaginationConfig } from '../../blocks/config/uib-pagination.config'; + +@Component({ + selector: 'jhi-audit', + templateUrl: './audits.component.html' +}) +export class AuditsComponent implements OnInit { + audits: Audit[]; + fromDate: string; + itemsPerPage: any; + links: any; + page: number; + orderProp: string; + reverse: boolean; + toDate: string; + totalItems: number; + + constructor( + private jhiLanguageService: JhiLanguageService, + private auditsService: AuditsService, + private parseLinks: ParseLinks, + private paginationConfig: PaginationConfig, + private datePipe: DatePipe + ) { + this.jhiLanguageService.setLocations(['audits']); + this.itemsPerPage = ITEMS_PER_PAGE; + this.page = 1; + this.reverse = false; + this.orderProp = 'timestamp'; + } + + getAudits() { + return this.sortAudits(this.audits); + } + + loadPage(page: number) { + this.page = page; + this.onChangeDate(); + } + + ngOnInit() { + this.today(); + this.previousMonth(); + this.onChangeDate(); + } + + onChangeDate() { + this.auditsService.query({page: this.page - 1, size: this.itemsPerPage, + fromDate: this.fromDate, toDate: this.toDate}).subscribe(res => { + + this.audits = res.json(); + this.links = this.parseLinks.parse(res.headers.get('link')); + this.totalItems = + res.headers.get('X-Total-Count'); + }); + } + + previousMonth() { + let dateFormat = 'yyyy-MM-dd'; + let fromDate: Date = new Date(); + + if (fromDate.getMonth() === 0) { + fromDate = new Date(fromDate.getFullYear() - 1, 11, fromDate.getDate()); + } else { + fromDate = new Date(fromDate.getFullYear(), fromDate.getMonth() - 1, fromDate.getDate()); + } + + this.fromDate = this.datePipe.transform(fromDate, dateFormat); + } + + today() { + let dateFormat = 'yyyy-MM-dd'; + // Today + 1 day - needed if the current day must be included + let today: Date = new Date(); + + let date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1); + this.toDate = this.datePipe.transform(date, dateFormat); + } + + private sortAudits(audits: Audit[]) { + audits = audits.slice(0).sort((a, b) => { + if (a[this.orderProp] < b[this.orderProp]) { + return -1; + } else if ([b[this.orderProp] < a[this.orderProp]]) { + return 1; + } else { + return 0; + } + }); + + return this.reverse ? audits.reverse() : audits; + } +} diff --git a/jhipster/src/main/webapp/app/admin/audits/audits.route.ts b/jhipster/src/main/webapp/app/admin/audits/audits.route.ts new file mode 100644 index 0000000000..f0e0fa7be9 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audits.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { AuditsComponent } from './audits.component'; + +export const auditsRoute: Route = { + path: 'audits', + component: AuditsComponent, + data: { + pageTitle: 'audits.title' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/audits/audits.service.ts b/jhipster/src/main/webapp/app/admin/audits/audits.service.ts new file mode 100644 index 0000000000..b373b8915c --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/audits/audits.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, URLSearchParams } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class AuditsService { + constructor(private http: Http) { } + + query(req: any): Observable { + let params: URLSearchParams = new URLSearchParams(); + params.set('fromDate', req.fromDate); + params.set('toDate', req.toDate); + params.set('page', req.page); + params.set('size', req.size); + params.set('sort', req.sort); + + let options = { + search: params + }; + + return this.http.get('management/audits', options); + } +} diff --git a/jhipster/src/main/webapp/app/admin/configuration/configuration.component.html b/jhipster/src/main/webapp/app/admin/configuration/configuration.component.html new file mode 100644 index 0000000000..1d64b41c29 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/configuration/configuration.component.html @@ -0,0 +1,46 @@ +
+

Configuration

+ + Filter (by prefix) + + + + + + + + + + + + + + +
PrefixProperties
{{entry.prefix}} +
+
{{key}}
+
+ {{entry.properties[key]}} +
+
+
+
+ + + + + + + + + + + + + + +
PropertyValue
{{item.key}} + {{item.val}} +
+
+
diff --git a/jhipster/src/main/webapp/app/admin/configuration/configuration.component.ts b/jhipster/src/main/webapp/app/admin/configuration/configuration.component.ts new file mode 100644 index 0000000000..88fbc32250 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/configuration/configuration.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { JhiConfigurationService } from './configuration.service'; + +@Component({ + selector: 'jhi-configuration', + templateUrl: './configuration.component.html' +}) +export class JhiConfigurationComponent implements OnInit { + allConfiguration: any = null; + configuration: any = null; + configKeys: any[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor( + private jhiLanguageService: JhiLanguageService, + private configurationService: JhiConfigurationService + ) { + this.jhiLanguageService.setLocations(['configuration']); + this.configKeys = []; + this.filter = ''; + this.orderProp = 'prefix'; + this.reverse = false; + } + + keys(dict): Array { + return (dict === undefined) ? [] : Object.keys(dict); + } + + ngOnInit() { + this.configurationService.get().subscribe((configuration) => { + this.configuration = configuration; + + for (let config of configuration) { + if (config.properties !== undefined) { + this.configKeys.push(Object.keys(config.properties)); + } + } + }); + + this.configurationService.getEnv().subscribe((configuration) => { + this.allConfiguration = configuration; + }); + } +} diff --git a/jhipster/src/main/webapp/app/admin/configuration/configuration.route.ts b/jhipster/src/main/webapp/app/admin/configuration/configuration.route.ts new file mode 100644 index 0000000000..06866237b0 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/configuration/configuration.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { JhiConfigurationComponent } from './configuration.component'; + +export const configurationRoute: Route = { + path: 'jhi-configuration', + component: JhiConfigurationComponent, + data: { + pageTitle: 'configuration.title' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/configuration/configuration.service.ts b/jhipster/src/main/webapp/app/admin/configuration/configuration.service.ts new file mode 100644 index 0000000000..e239ed3097 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/configuration/configuration.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class JhiConfigurationService { + + constructor(private http: Http) { + } + + get(): Observable { + return this.http.get('management/configprops').map((res: Response) => { + let properties: any[] = []; + + const propertiesObject = res.json(); + + for (let key in propertiesObject) { + if (propertiesObject.hasOwnProperty(key)) { + properties.push(propertiesObject[key]); + } + } + + return properties.sort((propertyA, propertyB) => { + return (propertyA.prefix === propertyB.prefix) ? 0 : + (propertyA.prefix < propertyB.prefix) ? -1 : 1; + }); + }); + } + + getEnv(): Observable { + return this.http.get('management/env').map((res: Response) => { + let properties: any = {}; + + const propertiesObject = res.json(); + + for (let key in propertiesObject) { + if (propertiesObject.hasOwnProperty(key)) { + let valsObject = propertiesObject[key]; + let vals: any[] = []; + + for (let valKey in valsObject) { + if (valsObject.hasOwnProperty(valKey)) { + vals.push({key: valKey, val: valsObject[valKey]}); + } + } + properties[key] = vals; + } + } + + return properties; + }); + } +} diff --git a/jhipster/src/main/webapp/app/admin/docs/docs.component.html b/jhipster/src/main/webapp/app/admin/docs/docs.component.html new file mode 100644 index 0000000000..30efbbb93e --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/docs/docs.component.html @@ -0,0 +1,2 @@ + diff --git a/jhipster/src/main/webapp/app/admin/docs/docs.component.ts b/jhipster/src/main/webapp/app/admin/docs/docs.component.ts new file mode 100644 index 0000000000..4bd5bf2329 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/docs/docs.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +@Component({ + selector: 'jhi-docs', + templateUrl: './docs.component.html' +}) +export class JhiDocsComponent { + constructor ( + private jhiLanguageService: JhiLanguageService + ) { + this.jhiLanguageService.setLocations(['global']); + } +} diff --git a/jhipster/src/main/webapp/app/admin/docs/docs.route.ts b/jhipster/src/main/webapp/app/admin/docs/docs.route.ts new file mode 100644 index 0000000000..6e99618f1d --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/docs/docs.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { JhiDocsComponent } from './docs.component'; + +export const docsRoute: Route = { + path: 'docs', + component: JhiDocsComponent, + data: { + pageTitle: 'global.menu.admin.apidocs' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/health/health-modal.component.html b/jhipster/src/main/webapp/app/admin/health/health-modal.component.html new file mode 100644 index 0000000000..1be6271f3b --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health-modal.component.html @@ -0,0 +1,36 @@ + + + diff --git a/jhipster/src/main/webapp/app/admin/health/health-modal.component.ts b/jhipster/src/main/webapp/app/admin/health/health-modal.component.ts new file mode 100644 index 0000000000..1486f20dbf --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health-modal.component.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiHealthService } from './health.service'; + +@Component({ + selector: 'jhi-health-modal', + templateUrl: './health-modal.component.html' +}) +export class JhiHealthModalComponent { + + currentHealth: any; + + constructor(private healthService: JhiHealthService, public activeModal: NgbActiveModal) {} + + baseName(name) { + return this.healthService.getBaseName(name); + } + + subSystemName(name) { + return this.healthService.getSubSystemName(name); + } + + readableValue(value: number) { + if (this.currentHealth.name !== 'diskSpace') { + return value.toString(); + } + + // Should display storage space in an human readable unit + let val = value / 1073741824; + if (val > 1) { // Value + return val.toFixed(2) + ' GB'; + } else { + return (value / 1048576).toFixed(2) + ' MB'; + } + } +} diff --git a/jhipster/src/main/webapp/app/admin/health/health.component.html b/jhipster/src/main/webapp/app/admin/health/health.component.html new file mode 100644 index 0000000000..6fea72af96 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health.component.html @@ -0,0 +1,34 @@ +
+

+ Health Checks + +

+
+ + + + + + + + + + + + + + + +
Service NameStatusDetails
{{'health.indicator.' + baseName(health.name) | translate}} {{subSystemName(health.name)}} + + {{health.status}} + + + + + +
+
+
diff --git a/jhipster/src/main/webapp/app/admin/health/health.component.ts b/jhipster/src/main/webapp/app/admin/health/health.component.ts new file mode 100644 index 0000000000..ab1be4271f --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health.component.ts @@ -0,0 +1,69 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { JhiHealthService } from './health.service'; +import { JhiHealthModalComponent } from './health-modal.component'; + +@Component({ + selector: 'jhi-health', + templateUrl: './health.component.html', +}) +export class JhiHealthCheckComponent implements OnInit { + healthData: any; + updatingHealth: boolean; + + constructor( + private jhiLanguageService: JhiLanguageService, + private modalService: NgbModal, + private healthService: JhiHealthService + ) { + this.jhiLanguageService.setLocations(['health']); + + } + + ngOnInit() { + this.refresh(); + } + + baseName(name: string) { + return this.healthService.getBaseName(name); + } + + getBadgeClass(statusState) { + if (statusState === 'UP') { + return 'badge-success'; + } else { + return 'badge-danger'; + } + } + + refresh() { + this.updatingHealth = true; + + this.healthService.checkHealth().subscribe(health => { + this.healthData = this.healthService.transformHealthData(health); + this.updatingHealth = false; + }, error => { + if (error.status === 503) { + this.healthData = this.healthService.transformHealthData(error.json()); + this.updatingHealth = false; + } + }); + } + + showHealth(health: any) { + const modalRef = this.modalService.open(JhiHealthModalComponent); + modalRef.componentInstance.currentHealth = health; + modalRef.result.then((result) => { + // Left blank intentionally, nothing to do here + }, (reason) => { + // Left blank intentionally, nothing to do here + }); + } + + subSystemName(name: string) { + return this.healthService.getSubSystemName(name); + } + +} diff --git a/jhipster/src/main/webapp/app/admin/health/health.route.ts b/jhipster/src/main/webapp/app/admin/health/health.route.ts new file mode 100644 index 0000000000..b47d07a0c0 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { JhiHealthCheckComponent } from './health.component'; + +export const healthRoute: Route = { + path: 'jhi-health', + component: JhiHealthCheckComponent, + data: { + pageTitle: 'health.title' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/health/health.service.ts b/jhipster/src/main/webapp/app/admin/health/health.service.ts new file mode 100644 index 0000000000..1bf00dab08 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/health/health.service.ts @@ -0,0 +1,140 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class JhiHealthService { + + separator: string; + + constructor (private http: Http) { + this.separator = '.'; + } + + checkHealth(): Observable { + return this.http.get('management/health').map((res: Response) => res.json()); + } + + transformHealthData(data): any { + let response = []; + this.flattenHealthData(response, null, data); + return response; + } + + getBaseName(name): string { + if (name) { + let split = name.split('.'); + return split[0]; + } + } + + getSubSystemName(name): string { + if (name) { + let split = name.split('.'); + split.splice(0, 1); + let remainder = split.join('.'); + return remainder ? ' - ' + remainder : ''; + } + } + + /* private methods */ + private addHealthObject(result, isLeaf, healthObject, name): any { + + let status: any; + let error: any; + let healthData: any = { + 'name': name, + 'error': error, + 'status': status + }; + + let details = {}; + let hasDetails = false; + + for (let key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + let value = healthObject[key]; + if (key === 'status' || key === 'error') { + healthData[key] = value; + } else { + if (!this.isHealthObject(value)) { + details[key] = value; + hasDetails = true; + } + } + } + } + + // Add the details + if (hasDetails) { + healthData.details = details; + } + + // Only add nodes if they provide additional information + if (isLeaf || hasDetails || healthData.error) { + result.push(healthData); + } + return healthData; + } + + private flattenHealthData (result, path, data): any { + for (let key in data) { + if (data.hasOwnProperty(key)) { + let value = data[key]; + if (this.isHealthObject(value)) { + if (this.hasSubSystem(value)) { + this.addHealthObject(result, false, value, this.getModuleName(path, key)); + this.flattenHealthData(result, this.getModuleName(path, key), value); + } else { + this.addHealthObject(result, true, value, this.getModuleName(path, key)); + } + } + } + } + + return result; + } + + private getModuleName (path, name): string { + let result; + if (path && name) { + result = path + this.separator + name; + } else if (path) { + result = path; + } else if (name) { + result = name; + } else { + result = ''; + } + return result; + } + + private hasSubSystem (healthObject): boolean { + let result = false; + + for (let key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + let value = healthObject[key]; + if (value && value.status) { + result = true; + } + } + } + + return result; + } + + private isHealthObject (healthObject): boolean { + let result = false; + + for (let key in healthObject) { + if (healthObject.hasOwnProperty(key)) { + if (key === 'status') { + result = true; + } + } + } + + return result; + } +} diff --git a/jhipster/src/main/webapp/app/admin/index.ts b/jhipster/src/main/webapp/app/admin/index.ts new file mode 100644 index 0000000000..2273c8af12 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/index.ts @@ -0,0 +1,29 @@ +export * from './audits/audits.component'; +export * from './audits/audits.service'; +export * from './audits/audits.route'; +export * from './audits/audit.model'; +export * from './audits/audit-data.model'; +export * from './configuration/configuration.component'; +export * from './configuration/configuration.service'; +export * from './configuration/configuration.route'; +export * from './docs/docs.component'; +export * from './docs/docs.route'; +export * from './health/health.component'; +export * from './health/health-modal.component'; +export * from './health/health.service'; +export * from './health/health.route'; +export * from './logs/logs.component'; +export * from './logs/logs.service'; +export * from './logs/logs.route'; +export * from './logs/log.model'; +export * from './metrics/metrics.component'; +export * from './metrics/metrics-modal.component'; +export * from './metrics/metrics.service'; +export * from './metrics/metrics.route'; +export * from './user-management/user-management-dialog.component'; +export * from './user-management/user-management-delete-dialog.component'; +export * from './user-management/user-management-detail.component'; +export * from './user-management/user-management.component'; +export * from './user-management/user-management.route'; +export * from './user-management/user-modal.service'; +export * from './admin.route'; diff --git a/jhipster/src/main/webapp/app/admin/logs/log.model.ts b/jhipster/src/main/webapp/app/admin/logs/log.model.ts new file mode 100644 index 0000000000..79cbd34808 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/logs/log.model.ts @@ -0,0 +1,6 @@ +export class Log { + constructor( + public name: string, + public level: string + ) { } +} diff --git a/jhipster/src/main/webapp/app/admin/logs/logs.component.html b/jhipster/src/main/webapp/app/admin/logs/logs.component.html new file mode 100644 index 0000000000..242ef5563a --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/logs/logs.component.html @@ -0,0 +1,27 @@ +
+

Logs

+ +

There are {{ loggers.length }} loggers.

+ + Filter + + + + + + + + + + + + + +
NameLevel
{{logger.name | slice:0:140}} + + + + + +
+
diff --git a/jhipster/src/main/webapp/app/admin/logs/logs.component.ts b/jhipster/src/main/webapp/app/admin/logs/logs.component.ts new file mode 100644 index 0000000000..7655749018 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/logs/logs.component.ts @@ -0,0 +1,38 @@ +import { Component, OnInit } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Log } from './log.model'; +import { LogsService } from './logs.service'; + +@Component({ + selector: 'jhi-logs', + templateUrl: './logs.component.html', +}) +export class LogsComponent implements OnInit { + + loggers: Log[]; + filter: string; + orderProp: string; + reverse: boolean; + + constructor ( + private jhiLanguageService: JhiLanguageService, + private logsService: LogsService + ) { + this.filter = ''; + this.orderProp = 'name'; + this.reverse = false; + this.jhiLanguageService.setLocations(['logs']); + } + + ngOnInit() { + this.logsService.findAll().subscribe(loggers => this.loggers = loggers); + } + + changeLevel (name: string, level: string) { + let log = new Log(name, level); + this.logsService.changeLevel(log).subscribe(() => { + this.logsService.findAll().subscribe(loggers => this.loggers = loggers); + }); + } +} diff --git a/jhipster/src/main/webapp/app/admin/logs/logs.route.ts b/jhipster/src/main/webapp/app/admin/logs/logs.route.ts new file mode 100644 index 0000000000..1077f5da32 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/logs/logs.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { LogsComponent } from './logs.component'; + +export const logsRoute: Route = { + path: 'logs', + component: LogsComponent, + data: { + pageTitle: 'logs.title' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/logs/logs.service.ts b/jhipster/src/main/webapp/app/admin/logs/logs.service.ts new file mode 100644 index 0000000000..c937c10a42 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/logs/logs.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import { Log } from './log.model'; + +@Injectable() +export class LogsService { + constructor(private http: Http) { } + + changeLevel(log: Log): Observable { + return this.http.put('management/logs', log); + } + + findAll(): Observable { + return this.http.get('management/logs').map((res: Response) => res.json()); + } +} diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.html b/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.html new file mode 100644 index 0000000000..b8f0391acf --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.html @@ -0,0 +1,56 @@ + + + + diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.ts b/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.ts new file mode 100644 index 0000000000..4a3034dd94 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics-modal.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'jhi-metrics-modal', + templateUrl: './metrics-modal.component.html' +}) +export class JhiMetricsMonitoringModalComponent implements OnInit { + + threadDumpFilter: any; + threadDump: any; + threadDumpAll = 0; + threadDumpBlocked = 0; + threadDumpRunnable = 0; + threadDumpTimedWaiting = 0; + threadDumpWaiting = 0; + + constructor(public activeModal: NgbActiveModal) {} + + ngOnInit() { + this.threadDump.forEach((value) => { + if (value.threadState === 'RUNNABLE') { + this.threadDumpRunnable += 1; + } else if (value.threadState === 'WAITING') { + this.threadDumpWaiting += 1; + } else if (value.threadState === 'TIMED_WAITING') { + this.threadDumpTimedWaiting += 1; + } else if (value.threadState === 'BLOCKED') { + this.threadDumpBlocked += 1; + } + }); + + this.threadDumpAll = this.threadDumpRunnable + this.threadDumpWaiting + + this.threadDumpTimedWaiting + this.threadDumpBlocked; + } + + getBadgeClass (threadState) { + if (threadState === 'RUNNABLE') { + return 'badge-success'; + } else if (threadState === 'WAITING') { + return 'badge-info'; + } else if (threadState === 'TIMED_WAITING') { + return 'badge-warning'; + } else if (threadState === 'BLOCKED') { + return 'badge-danger'; + } + } +} diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics.component.html b/jhipster/src/main/webapp/app/admin/metrics/metrics.component.html new file mode 100644 index 0000000000..800ca21ef9 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics.component.html @@ -0,0 +1,253 @@ +
+

+ Application Metrics + +

+ +

JVM Metrics

+
+
+ Memory +

Total Memory ({{metrics.gauges['jvm.memory.total.used'].value / 1000000 | number:'1.0-0'}}M / {{metrics.gauges['jvm.memory.total.max'].value / 1000000 | number:'1.0-0'}}M)

+ + {{metrics.gauges['jvm.memory.total.used'].value * 100 / metrics.gauges['jvm.memory.total.max'].value | number:'1.0-0'}}% + +

Heap Memory ({{metrics.gauges['jvm.memory.heap.used'].value / 1000000 | number:'1.0-0'}}M / {{metrics.gauges['jvm.memory.heap.max'].value / 1000000 | number:'1.0-0'}}M)

+ + {{metrics.gauges['jvm.memory.heap.used'].value * 100 / metrics.gauges['jvm.memory.heap.max'].value | number:'1.0-0'}}% + +

Non-Heap Memory ({{metrics.gauges['jvm.memory.non-heap.used'].value / 1000000 | number:'1.0-0'}}M / {{metrics.gauges['jvm.memory.non-heap.committed'].value / 1000000 | number:'1.0-0'}}M)

+ + {{metrics.gauges['jvm.memory.non-heap.used'].value * 100 / metrics.gauges['jvm.memory.non-heap.committed'].value | number:'1.0-0'}}% + +
+
+ Threads (Total: {{metrics.gauges['jvm.threads.count'].value}}) +

Runnable {{metrics.gauges['jvm.threads.runnable.count'].value}}

+ + {{metrics.gauges['jvm.threads.runnable.count'].value * 100 / metrics.gauges['jvm.threads.count'].value | number:'1.0-0'}}% + +

Timed Waiting ({{metrics.gauges['jvm.threads.timed_waiting.count'].value}})

+ + {{metrics.gauges['jvm.threads.timed_waiting.count'].value * 100 / metrics.gauges['jvm.threads.count'].value | number:'1.0-0'}}% + +

Waiting ({{metrics.gauges['jvm.threads.waiting.count'].value}})

+ + {{metrics.gauges['jvm.threads.waiting.count'].value * 100 / metrics.gauges['jvm.threads.count'].value | number:'1.0-0'}}% + +

Blocked ({{metrics.gauges['jvm.threads.blocked.count'].value}})

+ + {{metrics.gauges['jvm.threads.blocked.count'].value * 100 / metrics.gauges['jvm.threads.count'].value | number:'1.0-0'}}% + +
+
+ Garbage collections +
+
Mark Sweep count
+
{{metrics.gauges['jvm.garbage.PS-MarkSweep.count'].value}}
+
+
+
Mark Sweep time
+
{{metrics.gauges['jvm.garbage.PS-MarkSweep.time'].value}}ms
+
+
+
Scavenge count
+
{{metrics.gauges['jvm.garbage.PS-Scavenge.count'].value}}
+
+
+
Scavenge time
+
{{metrics.gauges['jvm.garbage.PS-Scavenge.time'].value}}ms
+
+
+
+
Updating...
+ +

HTTP requests (events per second)

+

+ Active requests {{metrics.counters['com.codahale.metrics.servlet.InstrumentedFilter.activeRequests'].count | number:'1.0-0'}} - Total requests {{metrics.timers['com.codahale.metrics.servlet.InstrumentedFilter.requests'].count | number:'1.0-0'}} +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeCountMeanAverage (1 min)Average (5 min)Average (15 min)
OK + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].count}} + + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].mean_rate | number:'1.0-2'}} + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m1_rate | number:'1.0-2'}} + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m5_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m15_rate | number:'1.0-2'}} +
Not Found + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].count}} + + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].mean_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m1_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m5_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m15_rate | number:'1.0-2'}} +
Server error + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].count}} + + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].mean_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m1_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m5_rate | number:'1.0-2'}} + + {{metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m15_rate | number:'1.0-2'}} +
+
+ +

Services statistics (time in millisecond)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Service nameCountMeanMinp50p75p95p99Max
{{entry.key}}{{entry.value.count}}{{entry.value.mean * 1000 | number:'1.0-0'}}{{entry.value.min * 1000 | number:'1.0-0'}}{{entry.value.p50 * 1000 | number:'1.0-0'}}{{entry.value.p75 * 1000 | number:'1.0-0'}}{{entry.value.p95 * 1000 | number:'1.0-0'}}{{entry.value.p99 * 1000 | number:'1.0-0'}}{{entry.value.max * 1000 | number:'1.0-0'}}
+
+ +

Cache statistics

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cache nameCache HitsCache MissesCache GetsCache PutsCache RemovalsCache EvictionsCache Hit %Cache Miss %Average get time (µs)Average put time (µs)Average remove time (µs)
{{entry.key}}{{metrics.gauges[entry.key + '.cache-hits'].value}}{{metrics.gauges[entry.key + '.cache-misses'].value}}{{metrics.gauges[entry.key + '.cache-gets'].value}}{{metrics.gauges[entry.key + '.cache-puts'].value}}{{metrics.gauges[entry.key + '.cache-removals'].value}}{{metrics.gauges[entry.key + '.cache-evictions'].value}}{{metrics.gauges[entry.key + '.cache-hit-percentage'].value}}{{metrics.gauges[entry.key + '.cache-miss-percentage'].value }}{{metrics.gauges[entry.key + '.average-get-time'].value | number : '1.2-2' }}{{metrics.gauges[entry.key + '.average-put-time'].value | number : '1.2-2'}}{{metrics.gauges[entry.key + '.average-remove-time'].value | number : '1.2-2' }}
+
+ +

DataSource statistics (time in millisecond)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Usage ({{metrics.gauges['HikariPool-1.pool.ActiveConnections'].value}} / {{metrics.gauges['HikariPool-1.pool.TotalConnections'].value}})CountMeanMinp50p75p95p99Max
+
+ + {{metrics.gauges['HikariPool-1.pool.ActiveConnections'].value * 100 / metrics.gauges['HikariPool-1.pool.TotalConnections'].value | number:'1.0-0'}}% + +
+
{{metrics.histograms['HikariPool-1.pool.Usage'].count}}{{metrics.histograms['HikariPool-1.pool.Usage'].mean | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].min | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].p50 | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].p75 | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].p95 | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].p99 | number:'1.0-2'}}{{metrics.histograms['HikariPool-1.pool.Usage'].max | number:'1.0-2'}}
+
+
diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics.component.ts b/jhipster/src/main/webapp/app/admin/metrics/metrics.component.ts new file mode 100644 index 0000000000..21c39a3deb --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics.component.ts @@ -0,0 +1,74 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { JhiMetricsMonitoringModalComponent } from './metrics-modal.component'; +import { JhiMetricsService } from './metrics.service'; + +@Component({ + selector: 'jhi-metrics', + templateUrl: './metrics.component.html', +}) +export class JhiMetricsMonitoringComponent implements OnInit { + metrics: any = {}; + cachesStats: any = {}; + servicesStats: any = {}; + updatingMetrics = true; + JCACHE_KEY: string ; + + constructor( + private jhiLanguageService: JhiLanguageService, + private modalService: NgbModal, + private metricsService: JhiMetricsService + ) { + this.JCACHE_KEY = 'jcache.statistics'; + this.jhiLanguageService.setLocations(['metrics']); + } + + ngOnInit() { + this.refresh(); + } + + refresh () { + this.updatingMetrics = true; + this.metricsService.getMetrics().subscribe((metrics) => { + this.metrics = metrics; + this.updatingMetrics = false; + this.servicesStats = {}; + this.cachesStats = {}; + Object.keys(metrics.timers).forEach((key) => { + let value = metrics.timers[key]; + if (key.indexOf('web.rest') !== -1 || key.indexOf('service') !== -1) { + this.servicesStats[key] = value; + } + }); + Object.keys(metrics.gauges).forEach((key) => { + if (key.indexOf('jcache.statistics') !== -1) { + let value = metrics.gauges[key].value; + // remove gets or puts + let index = key.lastIndexOf('.'); + let newKey = key.substr(0, index); + + // Keep the name of the domain + this.cachesStats[newKey] = { + 'name': this.JCACHE_KEY.length, + 'value': value + }; + } + }); + }); + } + + refreshThreadDumpData () { + this.metricsService.threadDump().subscribe((data) => { + const modalRef = this.modalService.open(JhiMetricsMonitoringModalComponent, { size: 'lg'}); + modalRef.componentInstance.threadDump = data; + modalRef.result.then((result) => { + // Left blank intentionally, nothing to do here + }, (reason) => { + // Left blank intentionally, nothing to do here + }); + }); + } + +} diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics.route.ts b/jhipster/src/main/webapp/app/admin/metrics/metrics.route.ts new file mode 100644 index 0000000000..cc13284dc8 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics.route.ts @@ -0,0 +1,12 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { JhiMetricsMonitoringComponent } from './metrics.component'; + +export const metricsRoute: Route = { + path: 'jhi-metrics', + component: JhiMetricsMonitoringComponent, + data: { + pageTitle: 'metrics.title' + } +}; diff --git a/jhipster/src/main/webapp/app/admin/metrics/metrics.service.ts b/jhipster/src/main/webapp/app/admin/metrics/metrics.service.ts new file mode 100644 index 0000000000..2b31947339 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/metrics/metrics.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class JhiMetricsService { + + constructor (private http: Http) {} + + getMetrics(): Observable { + return this.http.get('management/metrics').map((res: Response) => res.json()); + } + + threadDump(): Observable { + return this.http.get('management/dump').map((res: Response) => res.json()); + } +} diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html b/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html new file mode 100644 index 0000000000..452f1612c8 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts b/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts new file mode 100644 index 0000000000..2c5c2a6a01 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-delete-dialog.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, JhiLanguageService } from 'ng-jhipster'; + +import { User, UserService } from '../../shared'; +import { UserModalService } from './user-modal.service'; + +@Component({ + selector: 'jhi-user-mgmt-delete-dialog', + templateUrl: './user-management-delete-dialog.component.html' +}) +export class UserMgmtDeleteDialogComponent { + + user: User; + + constructor( + private jhiLanguageService: JhiLanguageService, + private userService: UserService, + public activeModal: NgbActiveModal, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['user-management']); + } + + clear () { + this.activeModal.dismiss('cancel'); + } + + confirmDelete (login) { + this.userService.delete(login).subscribe(response => { + this.eventManager.broadcast({ name: 'userListModification', + content: 'Deleted a user'}); + this.activeModal.dismiss(true); + }); + } + +} + +@Component({ + selector: 'jhi-user-delete-dialog', + template: '' +}) +export class UserDeleteDialogComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private userModalService: UserModalService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + this.modalRef = this.userModalService.open(UserMgmtDeleteDialogComponent, params['login']); + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.html b/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.html new file mode 100644 index 0000000000..d5deb8fa24 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.html @@ -0,0 +1,44 @@ +
+

+ User [{{user.login}}] +

+
+
Login
+
+ {{user.login}} + Deactivated + Activated +
+
First Name
+
{{user.firstName}}
+
Last Name
+
{{user.lastName}}
+
Email
+
{{user.email}}
+
Lang Key
+
{{user.langKey}}
+
Created By
+
{{user.createdBy}}
+
Created Date
+
{{user.createdDate | date:'dd/MM/yy HH:mm' }}
+
Last Modified By
+
{{user.lastModifiedBy}}
+
Last Modified Date
+
{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}}
+
Profiles
+
+
    +
  • + {{authority}} +
  • +
+
+
+ +
diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.ts b/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.ts new file mode 100644 index 0000000000..564b1daf3d --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-detail.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { User, UserService } from '../../shared'; + +@Component({ + selector: 'jhi-user-mgmt-detail', + templateUrl: './user-management-detail.component.html' +}) +export class UserMgmtDetailComponent implements OnInit, OnDestroy { + + user: User; + private subscription: any; + + constructor( + private jhiLanguageService: JhiLanguageService, + private userService: UserService, + private route: ActivatedRoute + ) { + this.jhiLanguageService.setLocations(['user-management']); + } + + ngOnInit() { + this.subscription = this.route.params.subscribe(params => { + this.load(params['login']); + }); + } + + load (login) { + this.userService.find(login).subscribe(user => { + this.user = user; + }); + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + +} diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.html b/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.html new file mode 100644 index 0000000000..6359527df7 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.html @@ -0,0 +1,112 @@ +
+ + + + +
diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.ts b/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.ts new file mode 100644 index 0000000000..ebbf073df4 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management-dialog.component.ts @@ -0,0 +1,89 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, JhiLanguageService } from 'ng-jhipster'; + +import { UserModalService } from './user-modal.service'; +import { JhiLanguageHelper, User, UserService } from '../../shared'; + +@Component({ + selector: 'jhi-user-mgmt-dialog', + templateUrl: './user-management-dialog.component.html' +}) +export class UserMgmtDialogComponent implements OnInit { + + user: User; + languages: any[]; + authorities: any[]; + isSaving: Boolean; + + constructor ( + public activeModal: NgbActiveModal, + private languageHelper: JhiLanguageHelper, + private jhiLanguageService: JhiLanguageService, + private userService: UserService, + private eventManager: EventManager + ) {} + + ngOnInit() { + this.isSaving = false; + this.authorities = ['ROLE_USER', 'ROLE_ADMIN']; + this.languageHelper.getAll().then((languages) => { + this.languages = languages; + }); + this.jhiLanguageService.setLocations(['user-management']); + } + + clear() { + this.activeModal.dismiss('cancel'); + } + + save() { + this.isSaving = true; + if (this.user.id !== null) { + this.userService.update(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } else { + this.userService.create(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError()); + } + } + + private onSaveSuccess(result) { + this.eventManager.broadcast({ name: 'userListModification', content: 'OK' }); + this.isSaving = false; + this.activeModal.dismiss(result); + } + + private onSaveError() { + this.isSaving = false; + } +} + +@Component({ + selector: 'jhi-user-dialog', + template: '' +}) +export class UserDialogComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private userModalService: UserModalService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + if ( params['login'] ) { + this.modalRef = this.userModalService.open(UserMgmtDialogComponent, params['login']); + } else { + this.modalRef = this.userModalService.open(UserMgmtDialogComponent); + } + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management.component.html b/jhipster/src/main/webapp/app/admin/user-management/user-management.component.html new file mode 100644 index 0000000000..73fc18469a --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management.component.html @@ -0,0 +1,81 @@ +
+

+ Users + +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDLogin Email Lang Key ProfilesCreated Date Last Modified By Last Modified Date
{{user.id}}{{user.login}}{{user.email}} + Deactivated + Activated + {{user.langKey}} +
+ {{ authority }} +
+
{{user.createdDate | date:'dd/MM/yy HH:mm'}}{{user.lastModifiedBy}}{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}} +
+ + + +
+
+
+
+
+ +
+
+ +
+
+
diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management.component.ts b/jhipster/src/main/webapp/app/admin/user-management/user-management.component.ts new file mode 100644 index 0000000000..213bb24923 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management.component.ts @@ -0,0 +1,131 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Response } from '@angular/http'; +import { ActivatedRoute, Router } from '@angular/router'; +import { EventManager, PaginationUtil, ParseLinks, AlertService, JhiLanguageService } from 'ng-jhipster'; + +import { ITEMS_PER_PAGE, Principal, User, UserService } from '../../shared'; +import { PaginationConfig } from '../../blocks/config/uib-pagination.config'; + +@Component({ + selector: 'jhi-user-mgmt', + templateUrl: './user-management.component.html' +}) +export class UserMgmtComponent implements OnInit, OnDestroy { + + currentAccount: any; + users: User[]; + error: any; + success: any; + routeData: any; + links: any; + totalItems: any; + queryCount: any; + itemsPerPage: any; + page: any; + predicate: any; + previousPage: any; + reverse: any; + + constructor( + private jhiLanguageService: JhiLanguageService, + private userService: UserService, + private parseLinks: ParseLinks, + private alertService: AlertService, + private principal: Principal, + private eventManager: EventManager, private paginationUtil: PaginationUtil, + private paginationConfig: PaginationConfig, + private activatedRoute: ActivatedRoute, + private router: Router + ) { + this.itemsPerPage = ITEMS_PER_PAGE; + this.routeData = this.activatedRoute.data.subscribe(data => { + this.page = data['pagingParams'].page; + this.previousPage = data['pagingParams'].page; + this.reverse = data['pagingParams'].ascending; + this.predicate = data['pagingParams'].predicate; + }); + this.jhiLanguageService.setLocations(['user-management']); + } + + ngOnInit() { + this.principal.identity().then((account) => { + this.currentAccount = account; + this.loadAll(); + this.registerChangeInUsers(); + }); + } + + ngOnDestroy() { + this.routeData.unsubscribe(); + } + + registerChangeInUsers() { + this.eventManager.subscribe('userListModification', (response) => this.loadAll()); + } + + setActive (user, isActivated) { + user.activated = isActivated; + + this.userService.update(user).subscribe( + response => { + if (response.status === 200) { + this.error = null; + this.success = 'OK'; + this.loadAll(); + } else { + this.success = null; + this.error = 'ERROR'; + } + }); + } + + loadAll () { + this.userService.query({ + page: this.page - 1, + size: this.itemsPerPage, + sort: this.sort()}).subscribe( + (res: Response) => this.onSuccess(res.json(), res.headers), + (res: Response) => this.onError(res.json()) + ); + } + + trackIdentity (index, item: User) { + return item.id; + } + + sort () { + let result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + loadPage (page: number) { + if (page !== this.previousPage) { + this.previousPage = page; + this.transition(); + } + } + + transition () { + this.router.navigate(['/user-management'], { queryParams: + { + page: this.page, + sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc') + } + }); + this.loadAll(); + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + this.queryCount = this.totalItems; + this.users = data; + } + + private onError(error) { + this.alertService.error(error.error, error.message, null); + } +} diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-management.route.ts b/jhipster/src/main/webapp/app/admin/user-management/user-management.route.ts new file mode 100644 index 0000000000..6aca0cdeb1 --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-management.route.ts @@ -0,0 +1,77 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { PaginationUtil } from 'ng-jhipster'; + +import { UserMgmtComponent } from './user-management.component'; +import { UserMgmtDetailComponent } from './user-management-detail.component'; +import { UserDialogComponent } from './user-management-dialog.component'; +import { UserDeleteDialogComponent } from './user-management-delete-dialog.component'; + +import { Principal } from '../../shared'; + + +@Injectable() +export class UserResolve implements CanActivate { + + constructor(private principal: Principal) { } + + canActivate() { + return this.principal.identity().then(account => this.principal.hasAnyAuthority(['ROLE_ADMIN'])); + } +} + +@Injectable() +export class UserResolvePagingParams implements Resolve { + + constructor(private paginationUtil: PaginationUtil) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + let page = route.queryParams['page'] ? route.queryParams['page'] : '1'; + let sort = route.queryParams['sort'] ? route.queryParams['sort'] : 'id,asc'; + return { + page: this.paginationUtil.parsePage(page), + predicate: this.paginationUtil.parsePredicate(sort), + ascending: this.paginationUtil.parseAscending(sort) + }; + } +} + +export const userMgmtRoute: Routes = [ + { + path: 'user-management', + component: UserMgmtComponent, + resolve: { + 'pagingParams': UserResolvePagingParams + }, + data: { + pageTitle: 'userManagement.home.title' + } + }, + { + path: 'user-management/:login', + component: UserMgmtDetailComponent, + data: { + pageTitle: 'userManagement.home.title' + } + } +]; + +export const userDialogRoute: Routes = [ + { + path: 'user-management-new', + component: UserDialogComponent, + outlet: 'popup' + }, + { + path: 'user-management/:login/edit', + component: UserDialogComponent, + outlet: 'popup' + }, + { + path: 'user-management/:login/delete', + component: UserDeleteDialogComponent, + outlet: 'popup' + } +]; diff --git a/jhipster/src/main/webapp/app/admin/user-management/user-modal.service.ts b/jhipster/src/main/webapp/app/admin/user-management/user-modal.service.ts new file mode 100644 index 0000000000..006bc2a53c --- /dev/null +++ b/jhipster/src/main/webapp/app/admin/user-management/user-modal.service.ts @@ -0,0 +1,42 @@ +import { Injectable, Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { UserMgmtDialogComponent } from './user-management-dialog.component'; +import { User, UserService } from '../../shared'; + +@Injectable() +export class UserModalService { + private isOpen = false; + constructor ( + private modalService: NgbModal, + private router: Router, + private userService: UserService + ) {} + + open (component: Component, login?: string): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + + if (login) { + this.userService.find(login).subscribe(user => this.userModalRef(component, user)); + } else { + return this.userModalRef(component, new User()); + } + } + + userModalRef(component: Component, user: User): NgbModalRef { + let modalRef = this.modalService.open(component, { size: 'lg', backdrop: 'static'}); + modalRef.componentInstance.user = user; + modalRef.result.then(result => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }, (reason) => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }); + return modalRef; + } +} diff --git a/jhipster/src/main/webapp/app/app.constants.ts b/jhipster/src/main/webapp/app/app.constants.ts new file mode 100644 index 0000000000..8f53b6f2e8 --- /dev/null +++ b/jhipster/src/main/webapp/app/app.constants.ts @@ -0,0 +1,7 @@ +// DO NOT EDIT THIS FILE, EDIT THE WEBPACK COMMON CONFIG INSTEAD, WHICH WILL MODIFY THIS FILE +let _VERSION = '0.0.0'; // This value will be overwritten by webpack +let _DEBUG_INFO_ENABLED = true; // This value will be overwritten by webpack +/* @toreplace VERSION */ +/* @toreplace DEBUG_INFO_ENABLED */ +export const VERSION = _VERSION; +export const DEBUG_INFO_ENABLED = _DEBUG_INFO_ENABLED; diff --git a/jhipster/src/main/webapp/app/app.main.ts b/jhipster/src/main/webapp/app/app.main.ts new file mode 100644 index 0000000000..301e5ffb81 --- /dev/null +++ b/jhipster/src/main/webapp/app/app.main.ts @@ -0,0 +1,11 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { ProdConfig } from './blocks/config/prod.config'; +import { BaeldungAppModule } from './app.module'; + +ProdConfig(); + +if (module['hot']) { + module['hot'].accept(); +} + +platformBrowserDynamic().bootstrapModule(BaeldungAppModule); diff --git a/jhipster/src/main/webapp/app/app.module.ts b/jhipster/src/main/webapp/app/app.module.ts new file mode 100644 index 0000000000..dc82c6cdce --- /dev/null +++ b/jhipster/src/main/webapp/app/app.module.ts @@ -0,0 +1,58 @@ +import './vendor.ts'; + +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { BrowserModule } from '@angular/platform-browser'; +import { Ng2Webstorage } from 'ng2-webstorage'; + +import { BaeldungSharedModule, UserRouteAccessService } from './shared'; +import { BaeldungHomeModule } from './home/home.module'; +import { BaeldungAdminModule } from './admin/admin.module'; +import { BaeldungAccountModule } from './account/account.module'; +import { BaeldungEntityModule } from './entities/entity.module'; + +import { LayoutRoutingModule } from './layouts'; +import { customHttpProvider } from './blocks/interceptor/http.provider'; +import { PaginationConfig } from './blocks/config/uib-pagination.config'; + +import { + JhiMainComponent, + NavbarComponent, + FooterComponent, + ProfileService, + PageRibbonComponent, + ActiveMenuDirective, + ErrorComponent +} from './layouts'; + + +@NgModule({ + imports: [ + BrowserModule, + LayoutRoutingModule, + Ng2Webstorage.forRoot({ prefix: 'jhi', separator: '-'}), + BaeldungSharedModule, + BaeldungHomeModule, + BaeldungAdminModule, + BaeldungAccountModule, + BaeldungEntityModule + ], + declarations: [ + JhiMainComponent, + NavbarComponent, + ErrorComponent, + PageRibbonComponent, + ActiveMenuDirective, + FooterComponent + ], + providers: [ + ProfileService, + { provide: Window, useValue: window }, + { provide: Document, useValue: document }, + customHttpProvider(), + PaginationConfig, + UserRouteAccessService + ], + bootstrap: [ JhiMainComponent ] +}) +export class BaeldungAppModule {} diff --git a/jhipster/src/main/webapp/app/app.route.ts b/jhipster/src/main/webapp/app/app.route.ts new file mode 100644 index 0000000000..bfddd9bb7e --- /dev/null +++ b/jhipster/src/main/webapp/app/app.route.ts @@ -0,0 +1,9 @@ +import { Route } from '@angular/router'; + +import { NavbarComponent } from './layouts'; + +export const navbarRoute: Route = { + path: '', + component: NavbarComponent, + outlet: 'navbar' + }; diff --git a/jhipster/src/main/webapp/app/blocks/config/prod.config.ts b/jhipster/src/main/webapp/app/blocks/config/prod.config.ts new file mode 100644 index 0000000000..cc0050de27 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/config/prod.config.ts @@ -0,0 +1,9 @@ +import { enableProdMode } from '@angular/core'; +import { DEBUG_INFO_ENABLED } from '../../app.constants'; + +export function ProdConfig() { + // disable debug data on prod profile to improve performance + if (!DEBUG_INFO_ENABLED) { + enableProdMode(); + } +} diff --git a/jhipster/src/main/webapp/app/blocks/config/uib-pagination.config.ts b/jhipster/src/main/webapp/app/blocks/config/uib-pagination.config.ts new file mode 100644 index 0000000000..245e1f6bf1 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/config/uib-pagination.config.ts @@ -0,0 +1,13 @@ +import { ITEMS_PER_PAGE } from '../../shared'; +import { Injectable } from '@angular/core'; +import { NgbPaginationConfig} from '@ng-bootstrap/ng-bootstrap'; + +@Injectable() +export class PaginationConfig { + constructor(private config: NgbPaginationConfig) { + config.boundaryLinks = true; + config.maxSize = 5; + config.pageSize = ITEMS_PER_PAGE; + config.size = 'sm'; + } +} diff --git a/jhipster/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts b/jhipster/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts new file mode 100644 index 0000000000..49f517148c --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.ts @@ -0,0 +1,34 @@ +import { HttpInterceptor } from 'ng-jhipster'; +import { RequestOptionsArgs, Response } from '@angular/http'; +import { Observable } from 'rxjs/Observable'; +import { Injector } from '@angular/core'; +import { AuthService } from '../../shared/auth/auth.service'; +import { Principal } from '../../shared/auth/principal.service'; +import { AuthServerProvider } from '../../shared/auth/auth-jwt.service'; + +export class AuthExpiredInterceptor extends HttpInterceptor { + + constructor(private injector: Injector) { + super(); + } + + requestIntercept(options?: RequestOptionsArgs): RequestOptionsArgs { + return options; + } + + responseIntercept(observable: Observable): Observable { + let self = this; + + return > observable.catch((error, source) => { + if (error.status === 401) { + let principal: Principal = self.injector.get(Principal); + + if (principal.isAuthenticated()) { + let auth: AuthService = self.injector.get(AuthService); + auth.authorize(true); + } + } + return Observable.throw(error); + }); + } +} diff --git a/jhipster/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts b/jhipster/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts new file mode 100644 index 0000000000..cf90284116 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/interceptor/auth.interceptor.ts @@ -0,0 +1,27 @@ +import { Observable } from 'rxjs/Observable'; +import { RequestOptionsArgs, Response } from '@angular/http'; +import { LocalStorageService, SessionStorageService } from 'ng2-webstorage'; +import { HttpInterceptor } from 'ng-jhipster'; + +export class AuthInterceptor extends HttpInterceptor { + + constructor( + private localStorage: LocalStorageService, + private sessionStorage: SessionStorageService + ) { + super(); + } + + requestIntercept(options?: RequestOptionsArgs): RequestOptionsArgs { + let token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken'); + if (!!token) { + options.headers.append('Authorization', 'Bearer ' + token); + } + return options; + } + + responseIntercept(observable: Observable): Observable { + return observable; // by pass + } + +} diff --git a/jhipster/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts b/jhipster/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts new file mode 100644 index 0000000000..6e22557d05 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.ts @@ -0,0 +1,24 @@ +import { HttpInterceptor, EventManager } from 'ng-jhipster'; +import { RequestOptionsArgs, Response } from '@angular/http'; +import { Observable } from 'rxjs/Observable'; + +export class ErrorHandlerInterceptor extends HttpInterceptor { + + constructor(private eventManager: EventManager) { + super(); + } + + requestIntercept(options?: RequestOptionsArgs): RequestOptionsArgs { + return options; + } + + responseIntercept(observable: Observable): Observable { + return > observable.catch(error => { + if (!(error.status === 401 && (error.text() === '' || + (error.json().path && error.json().path.indexOf('/api/account') === 0 )))) { + this.eventManager.broadcast( {name: 'baeldungApp.httpError', content: error}); + } + return Observable.throw(error); + }); + } +} diff --git a/jhipster/src/main/webapp/app/blocks/interceptor/http.provider.ts b/jhipster/src/main/webapp/app/blocks/interceptor/http.provider.ts new file mode 100644 index 0000000000..a9689662a3 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/interceptor/http.provider.ts @@ -0,0 +1,45 @@ +import { Injector } from '@angular/core'; +import { Http, XHRBackend, RequestOptions } from '@angular/http'; +import { EventManager, InterceptableHttp } from 'ng-jhipster'; + +import { AuthInterceptor } from './auth.interceptor'; +import { LocalStorageService, SessionStorageService } from 'ng2-webstorage'; +import { AuthExpiredInterceptor } from './auth-expired.interceptor'; +import { ErrorHandlerInterceptor } from './errorhandler.interceptor'; +import { NotificationInterceptor } from './notification.interceptor'; + +export function interceptableFactory( + backend: XHRBackend, + defaultOptions: RequestOptions, + localStorage: LocalStorageService, + sessionStorage: SessionStorageService, + injector: Injector, + eventManager: EventManager +) { + return new InterceptableHttp( + backend, + defaultOptions, + [ + new AuthInterceptor(localStorage, sessionStorage), + new AuthExpiredInterceptor(injector), + // Other interceptors can be added here + new ErrorHandlerInterceptor(eventManager), + new NotificationInterceptor() + ] + ); +}; + +export function customHttpProvider() { + return { + provide: Http, + useFactory: interceptableFactory, + deps: [ + XHRBackend, + RequestOptions, + LocalStorageService, + SessionStorageService, + Injector, + EventManager + ] + }; +}; diff --git a/jhipster/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts b/jhipster/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts new file mode 100644 index 0000000000..ebee7688c5 --- /dev/null +++ b/jhipster/src/main/webapp/app/blocks/interceptor/notification.interceptor.ts @@ -0,0 +1,33 @@ +import { HttpInterceptor } from 'ng-jhipster'; +import { RequestOptionsArgs, Response } from '@angular/http'; +import { Observable } from 'rxjs/Observable'; + +export class NotificationInterceptor extends HttpInterceptor { + + constructor() { + super(); + } + + requestIntercept(options?: RequestOptionsArgs): RequestOptionsArgs { + return options; + } + + responseIntercept(observable: Observable): Observable { + return > observable.catch((error) => { + let arr = Array.from(error.headers._headers); + let headers = []; + let i; + for (i = 0; i < arr.length; i++) { + if (arr[i][0].endsWith('app-alert') || arr[i][0].endsWith('app-params')) { + headers.push(arr[i][0]); + } + } + headers.sort(); + let alertKey = headers.length >= 1 ? error.headers.get(headers[0]) : null; + if (typeof alertKey === 'string') { + // AlertService.success(alertKey, { param: response.headers(headers[1])}); + } + return Observable.throw(error); + }); + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.html b/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.html new file mode 100644 index 0000000000..63540ec6bd --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.ts b/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.ts new file mode 100644 index 0000000000..29ef818ddf --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-delete-dialog.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, JhiLanguageService } from 'ng-jhipster'; + +import { Comment } from './comment.model'; +import { CommentPopupService } from './comment-popup.service'; +import { CommentService } from './comment.service'; + +@Component({ + selector: 'jhi-comment-delete-dialog', + templateUrl: './comment-delete-dialog.component.html' +}) +export class CommentDeleteDialogComponent { + + comment: Comment; + + constructor( + private jhiLanguageService: JhiLanguageService, + private commentService: CommentService, + public activeModal: NgbActiveModal, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['comment']); + } + + clear () { + this.activeModal.dismiss('cancel'); + } + + confirmDelete (id: number) { + this.commentService.delete(id).subscribe(response => { + this.eventManager.broadcast({ + name: 'commentListModification', + content: 'Deleted an comment' + }); + this.activeModal.dismiss(true); + }); + } +} + +@Component({ + selector: 'jhi-comment-delete-popup', + template: '' +}) +export class CommentDeletePopupComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private commentPopupService: CommentPopupService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + this.modalRef = this.commentPopupService + .open(CommentDeleteDialogComponent, params['id']); + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.html b/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.html new file mode 100644 index 0000000000..add5b9e208 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.html @@ -0,0 +1,35 @@ + +
+

Comment {{comment.id}}

+
+ +
+
Text
+
+ {{comment.text}} +
+
Creation Date
+
+ {{comment.creationDate | date:'mediumDate'}} +
+
Post
+
+ +
+
+ + + + +
diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.ts b/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.ts new file mode 100644 index 0000000000..c2bf7fce0f --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-detail.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { JhiLanguageService } from 'ng-jhipster'; +import { Comment } from './comment.model'; +import { CommentService } from './comment.service'; + +@Component({ + selector: 'jhi-comment-detail', + templateUrl: './comment-detail.component.html' +}) +export class CommentDetailComponent implements OnInit, OnDestroy { + + comment: Comment; + private subscription: any; + + constructor( + private jhiLanguageService: JhiLanguageService, + private commentService: CommentService, + private route: ActivatedRoute + ) { + this.jhiLanguageService.setLocations(['comment']); + } + + ngOnInit() { + this.subscription = this.route.params.subscribe(params => { + this.load(params['id']); + }); + } + + load (id) { + this.commentService.find(id).subscribe(comment => { + this.comment = comment; + }); + } + previousState() { + window.history.back(); + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.html b/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.html new file mode 100644 index 0000000000..7e13c33177 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.html @@ -0,0 +1,76 @@ + + +
+ + + + +
diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.ts b/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.ts new file mode 100644 index 0000000000..1a30305c96 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-dialog.component.ts @@ -0,0 +1,107 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Response } from '@angular/http'; + +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, AlertService, JhiLanguageService } from 'ng-jhipster'; + +import { Comment } from './comment.model'; +import { CommentPopupService } from './comment-popup.service'; +import { CommentService } from './comment.service'; +import { Post, PostService } from '../post'; +@Component({ + selector: 'jhi-comment-dialog', + templateUrl: './comment-dialog.component.html' +}) +export class CommentDialogComponent implements OnInit { + + comment: Comment; + authorities: any[]; + isSaving: boolean; + + posts: Post[]; + constructor( + public activeModal: NgbActiveModal, + private jhiLanguageService: JhiLanguageService, + private alertService: AlertService, + private commentService: CommentService, + private postService: PostService, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['comment']); + } + + ngOnInit() { + this.isSaving = false; + this.authorities = ['ROLE_USER', 'ROLE_ADMIN']; + this.postService.query().subscribe( + (res: Response) => { this.posts = res.json(); }, (res: Response) => this.onError(res.json())); + } + clear () { + this.activeModal.dismiss('cancel'); + } + + save () { + this.isSaving = true; + if (this.comment.id !== undefined) { + this.commentService.update(this.comment) + .subscribe((res: Comment) => + this.onSaveSuccess(res), (res: Response) => this.onSaveError(res.json())); + } else { + this.commentService.create(this.comment) + .subscribe((res: Comment) => + this.onSaveSuccess(res), (res: Response) => this.onSaveError(res.json())); + } + } + + private onSaveSuccess (result: Comment) { + this.eventManager.broadcast({ name: 'commentListModification', content: 'OK'}); + this.isSaving = false; + this.activeModal.dismiss(result); + } + + private onSaveError (error) { + this.isSaving = false; + this.onError(error); + } + + private onError (error) { + this.alertService.error(error.message, null, null); + } + + trackPostById(index: number, item: Post) { + return item.id; + } +} + +@Component({ + selector: 'jhi-comment-popup', + template: '' +}) +export class CommentPopupComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private commentPopupService: CommentPopupService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + if ( params['id'] ) { + this.modalRef = this.commentPopupService + .open(CommentDialogComponent, params['id']); + } else { + this.modalRef = this.commentPopupService + .open(CommentDialogComponent); + } + + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment-popup.service.ts b/jhipster/src/main/webapp/app/entities/comment/comment-popup.service.ts new file mode 100644 index 0000000000..a1c0ce11bf --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment-popup.service.ts @@ -0,0 +1,50 @@ +import { Injectable, Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { Comment } from './comment.model'; +import { CommentService } from './comment.service'; +@Injectable() +export class CommentPopupService { + private isOpen = false; + constructor ( + private modalService: NgbModal, + private router: Router, + private commentService: CommentService + + ) {} + + open (component: Component, id?: number | any): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + + if (id) { + this.commentService.find(id).subscribe(comment => { + if (comment.creationDate) { + comment.creationDate = { + year: comment.creationDate.getFullYear(), + month: comment.creationDate.getMonth() + 1, + day: comment.creationDate.getDate() + }; + } + this.commentModalRef(component, comment); + }); + } else { + return this.commentModalRef(component, new Comment()); + } + } + + commentModalRef(component: Component, comment: Comment): NgbModalRef { + let modalRef = this.modalService.open(component, { size: 'lg', backdrop: 'static'}); + modalRef.componentInstance.comment = comment; + modalRef.result.then(result => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }, (reason) => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }); + return modalRef; + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.component.html b/jhipster/src/main/webapp/app/entities/comment/comment.component.html new file mode 100644 index 0000000000..1efd1ce379 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.component.html @@ -0,0 +1,64 @@ +
+

+ Comments + +

+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + +
ID Text Creation Date Post
{{comment.id}}{{comment.text}}{{comment.creationDate | date:'mediumDate'}} + + +
+ + + +
+
+
+
diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.component.ts b/jhipster/src/main/webapp/app/entities/comment/comment.component.ts new file mode 100644 index 0000000000..4e009d4774 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.component.ts @@ -0,0 +1,110 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Response } from '@angular/http'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subscription } from 'rxjs/Rx'; +import { EventManager, ParseLinks, PaginationUtil, JhiLanguageService, AlertService } from 'ng-jhipster'; + +import { Comment } from './comment.model'; +import { CommentService } from './comment.service'; +import { ITEMS_PER_PAGE, Principal } from '../../shared'; +import { PaginationConfig } from '../../blocks/config/uib-pagination.config'; + +@Component({ + selector: 'jhi-comment', + templateUrl: './comment.component.html' +}) +export class CommentComponent implements OnInit, OnDestroy { + + comments: Comment[]; + currentAccount: any; + eventSubscriber: Subscription; + itemsPerPage: number; + links: any; + page: any; + predicate: any; + queryCount: any; + reverse: any; + totalItems: number; + + constructor( + private jhiLanguageService: JhiLanguageService, + private commentService: CommentService, + private alertService: AlertService, + private eventManager: EventManager, + private parseLinks: ParseLinks, + private principal: Principal + ) { + this.comments = []; + this.itemsPerPage = ITEMS_PER_PAGE; + this.page = 0; + this.links = { + last: 0 + }; + this.predicate = 'id'; + this.reverse = true; + this.jhiLanguageService.setLocations(['comment']); + } + + loadAll () { + this.commentService.query({ + page: this.page, + size: this.itemsPerPage, + sort: this.sort() + }).subscribe( + (res: Response) => this.onSuccess(res.json(), res.headers), + (res: Response) => this.onError(res.json()) + ); + } + + reset () { + this.page = 0; + this.comments = []; + this.loadAll(); + } + + loadPage(page) { + this.page = page; + this.loadAll(); + } + ngOnInit() { + this.loadAll(); + this.principal.identity().then((account) => { + this.currentAccount = account; + }); + this.registerChangeInComments(); + } + + ngOnDestroy() { + this.eventManager.destroy(this.eventSubscriber); + } + + trackId (index: number, item: Comment) { + return item.id; + } + + + + registerChangeInComments() { + this.eventSubscriber = this.eventManager.subscribe('commentListModification', (response) => this.reset()); + } + + sort () { + let result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + for (let i = 0; i < data.length; i++) { + this.comments.push(data[i]); + } + } + + private onError (error) { + this.alertService.error(error.message, null, null); + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.model.ts b/jhipster/src/main/webapp/app/entities/comment/comment.model.ts new file mode 100644 index 0000000000..66df7d0b34 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.model.ts @@ -0,0 +1,10 @@ +import { Post } from '../post'; +export class Comment { + constructor( + public id?: number, + public text?: string, + public creationDate?: any, + public post?: Post, + ) { + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.module.ts b/jhipster/src/main/webapp/app/entities/comment/comment.module.ts new file mode 100644 index 0000000000..1f3167274e --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.module.ts @@ -0,0 +1,50 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BaeldungSharedModule } from '../../shared'; + +import { + CommentService, + CommentPopupService, + CommentComponent, + CommentDetailComponent, + CommentDialogComponent, + CommentPopupComponent, + CommentDeletePopupComponent, + CommentDeleteDialogComponent, + commentRoute, + commentPopupRoute, +} from './'; + +let ENTITY_STATES = [ + ...commentRoute, + ...commentPopupRoute, +]; + +@NgModule({ + imports: [ + BaeldungSharedModule, + RouterModule.forRoot(ENTITY_STATES, { useHash: true }) + ], + declarations: [ + CommentComponent, + CommentDetailComponent, + CommentDialogComponent, + CommentDeleteDialogComponent, + CommentPopupComponent, + CommentDeletePopupComponent, + ], + entryComponents: [ + CommentComponent, + CommentDialogComponent, + CommentPopupComponent, + CommentDeleteDialogComponent, + CommentDeletePopupComponent, + ], + providers: [ + CommentService, + CommentPopupService, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungCommentModule {} diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.route.ts b/jhipster/src/main/webapp/app/entities/comment/comment.route.ts new file mode 100644 index 0000000000..bb0e5e4141 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.route.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { PaginationUtil } from 'ng-jhipster'; + +import { CommentComponent } from './comment.component'; +import { CommentDetailComponent } from './comment-detail.component'; +import { CommentPopupComponent } from './comment-dialog.component'; +import { CommentDeletePopupComponent } from './comment-delete-dialog.component'; + +import { Principal } from '../../shared'; + + +export const commentRoute: Routes = [ + { + path: 'comment', + component: CommentComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.comment.home.title' + } + }, { + path: 'comment/:id', + component: CommentDetailComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.comment.home.title' + } + } +]; + +export const commentPopupRoute: Routes = [ + { + path: 'comment-new', + component: CommentPopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.comment.home.title' + }, + outlet: 'popup' + }, + { + path: 'comment/:id/edit', + component: CommentPopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.comment.home.title' + }, + outlet: 'popup' + }, + { + path: 'comment/:id/delete', + component: CommentDeletePopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.comment.home.title' + }, + outlet: 'popup' + } +]; diff --git a/jhipster/src/main/webapp/app/entities/comment/comment.service.ts b/jhipster/src/main/webapp/app/entities/comment/comment.service.ts new file mode 100644 index 0000000000..b6121b3b10 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/comment.service.ts @@ -0,0 +1,78 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, URLSearchParams, BaseRequestOptions } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import { Comment } from './comment.model'; +import { DateUtils } from 'ng-jhipster'; +@Injectable() +export class CommentService { + + private resourceUrl = 'api/comments'; + + constructor(private http: Http, private dateUtils: DateUtils) { } + + create(comment: Comment): Observable { + let copy: Comment = Object.assign({}, comment); + copy.creationDate = this.dateUtils + .convertLocalDateToServer(comment.creationDate); + return this.http.post(this.resourceUrl, copy).map((res: Response) => { + return res.json(); + }); + } + + update(comment: Comment): Observable { + let copy: Comment = Object.assign({}, comment); + copy.creationDate = this.dateUtils + .convertLocalDateToServer(comment.creationDate); + return this.http.put(this.resourceUrl, copy).map((res: Response) => { + return res.json(); + }); + } + + find(id: number): Observable { + return this.http.get(`${this.resourceUrl}/${id}`).map((res: Response) => { + let jsonResponse = res.json(); + jsonResponse.creationDate = this.dateUtils + .convertLocalDateFromServer(jsonResponse.creationDate); + return jsonResponse; + }); + } + + query(req?: any): Observable { + let options = this.createRequestOption(req); + return this.http.get(this.resourceUrl, options) + .map((res: any) => this.convertResponse(res)) + ; + } + + delete(id: number): Observable { + return this.http.delete(`${this.resourceUrl}/${id}`); + } + + + private convertResponse(res: any): any { + let jsonResponse = res.json(); + for (let i = 0; i < jsonResponse.length; i++) { + jsonResponse[i].creationDate = this.dateUtils + .convertLocalDateFromServer(jsonResponse[i].creationDate); + } + res._body = jsonResponse; + return res; + } + + private createRequestOption(req?: any): BaseRequestOptions { + let options: BaseRequestOptions = new BaseRequestOptions(); + if (req) { + let params: URLSearchParams = new URLSearchParams(); + params.set('page', req.page); + params.set('size', req.size); + if (req.sort) { + params.paramsMap.set('sort', req.sort); + } + params.set('query', req.query); + + options.search = params; + } + return options; + } +} diff --git a/jhipster/src/main/webapp/app/entities/comment/index.ts b/jhipster/src/main/webapp/app/entities/comment/index.ts new file mode 100644 index 0000000000..5e54fb6099 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/comment/index.ts @@ -0,0 +1,8 @@ +export * from './comment.model'; +export * from './comment-popup.service'; +export * from './comment.service'; +export * from './comment-dialog.component'; +export * from './comment-delete-dialog.component'; +export * from './comment-detail.component'; +export * from './comment.component'; +export * from './comment.route'; diff --git a/jhipster/src/main/webapp/app/entities/entity.module.ts b/jhipster/src/main/webapp/app/entities/entity.module.ts new file mode 100644 index 0000000000..ba044e1902 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/entity.module.ts @@ -0,0 +1,18 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; + +import { BaeldungPostModule } from './post/post.module'; +import { BaeldungCommentModule } from './comment/comment.module'; +/* jhipster-needle-add-entity-module-import - JHipster will add entity modules imports here */ + +@NgModule({ + imports: [ + BaeldungPostModule, + BaeldungCommentModule, + /* jhipster-needle-add-entity-module - JHipster will add entity modules here */ + ], + declarations: [], + entryComponents: [], + providers: [], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungEntityModule {} diff --git a/jhipster/src/main/webapp/app/entities/post/index.ts b/jhipster/src/main/webapp/app/entities/post/index.ts new file mode 100644 index 0000000000..9375e11bd8 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/index.ts @@ -0,0 +1,8 @@ +export * from './post.model'; +export * from './post-popup.service'; +export * from './post.service'; +export * from './post-dialog.component'; +export * from './post-delete-dialog.component'; +export * from './post-detail.component'; +export * from './post.component'; +export * from './post.route'; diff --git a/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.html b/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.html new file mode 100644 index 0000000000..901fc1968e --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.html @@ -0,0 +1,19 @@ +
+ + + +
diff --git a/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.ts b/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.ts new file mode 100644 index 0000000000..5e1413fd95 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-delete-dialog.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, JhiLanguageService } from 'ng-jhipster'; + +import { Post } from './post.model'; +import { PostPopupService } from './post-popup.service'; +import { PostService } from './post.service'; + +@Component({ + selector: 'jhi-post-delete-dialog', + templateUrl: './post-delete-dialog.component.html' +}) +export class PostDeleteDialogComponent { + + post: Post; + + constructor( + private jhiLanguageService: JhiLanguageService, + private postService: PostService, + public activeModal: NgbActiveModal, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['post']); + } + + clear () { + this.activeModal.dismiss('cancel'); + } + + confirmDelete (id: number) { + this.postService.delete(id).subscribe(response => { + this.eventManager.broadcast({ + name: 'postListModification', + content: 'Deleted an post' + }); + this.activeModal.dismiss(true); + }); + } +} + +@Component({ + selector: 'jhi-post-delete-popup', + template: '' +}) +export class PostDeletePopupComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private postPopupService: PostPopupService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + this.modalRef = this.postPopupService + .open(PostDeleteDialogComponent, params['id']); + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/entities/post/post-detail.component.html b/jhipster/src/main/webapp/app/entities/post/post-detail.component.html new file mode 100644 index 0000000000..8edcbee375 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-detail.component.html @@ -0,0 +1,37 @@ + +
+

Post {{post.id}}

+
+ +
+
Title
+
+ {{post.title}} +
+
Content
+
+ {{post.content}} +
+
Creation Date
+
+ {{post.creationDate | date:'mediumDate'}} +
+
Creator
+
+ {{post.creator?.login}} +
+
+ + + + +
diff --git a/jhipster/src/main/webapp/app/entities/post/post-detail.component.ts b/jhipster/src/main/webapp/app/entities/post/post-detail.component.ts new file mode 100644 index 0000000000..679592f3b8 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-detail.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { JhiLanguageService } from 'ng-jhipster'; +import { Post } from './post.model'; +import { PostService } from './post.service'; + +@Component({ + selector: 'jhi-post-detail', + templateUrl: './post-detail.component.html' +}) +export class PostDetailComponent implements OnInit, OnDestroy { + + post: Post; + private subscription: any; + + constructor( + private jhiLanguageService: JhiLanguageService, + private postService: PostService, + private route: ActivatedRoute + ) { + this.jhiLanguageService.setLocations(['post']); + } + + ngOnInit() { + this.subscription = this.route.params.subscribe(params => { + this.load(params['id']); + }); + } + + load (id) { + this.postService.find(id).subscribe(post => { + this.post = post; + }); + } + previousState() { + window.history.back(); + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + +} diff --git a/jhipster/src/main/webapp/app/entities/post/post-dialog.component.html b/jhipster/src/main/webapp/app/entities/post/post-dialog.component.html new file mode 100644 index 0000000000..2216dcd451 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-dialog.component.html @@ -0,0 +1,96 @@ + + +
+ + + + +
diff --git a/jhipster/src/main/webapp/app/entities/post/post-dialog.component.ts b/jhipster/src/main/webapp/app/entities/post/post-dialog.component.ts new file mode 100644 index 0000000000..803b76fc78 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-dialog.component.ts @@ -0,0 +1,107 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Response } from '@angular/http'; + +import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, AlertService, JhiLanguageService } from 'ng-jhipster'; + +import { Post } from './post.model'; +import { PostPopupService } from './post-popup.service'; +import { PostService } from './post.service'; +import { User, UserService } from '../../shared'; +@Component({ + selector: 'jhi-post-dialog', + templateUrl: './post-dialog.component.html' +}) +export class PostDialogComponent implements OnInit { + + post: Post; + authorities: any[]; + isSaving: boolean; + + users: User[]; + constructor( + public activeModal: NgbActiveModal, + private jhiLanguageService: JhiLanguageService, + private alertService: AlertService, + private postService: PostService, + private userService: UserService, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['post']); + } + + ngOnInit() { + this.isSaving = false; + this.authorities = ['ROLE_USER', 'ROLE_ADMIN']; + this.userService.query().subscribe( + (res: Response) => { this.users = res.json(); }, (res: Response) => this.onError(res.json())); + } + clear () { + this.activeModal.dismiss('cancel'); + } + + save () { + this.isSaving = true; + if (this.post.id !== undefined) { + this.postService.update(this.post) + .subscribe((res: Post) => + this.onSaveSuccess(res), (res: Response) => this.onSaveError(res.json())); + } else { + this.postService.create(this.post) + .subscribe((res: Post) => + this.onSaveSuccess(res), (res: Response) => this.onSaveError(res.json())); + } + } + + private onSaveSuccess (result: Post) { + this.eventManager.broadcast({ name: 'postListModification', content: 'OK'}); + this.isSaving = false; + this.activeModal.dismiss(result); + } + + private onSaveError (error) { + this.isSaving = false; + this.onError(error); + } + + private onError (error) { + this.alertService.error(error.message, null, null); + } + + trackUserById(index: number, item: User) { + return item.id; + } +} + +@Component({ + selector: 'jhi-post-popup', + template: '' +}) +export class PostPopupComponent implements OnInit, OnDestroy { + + modalRef: NgbModalRef; + routeSub: any; + + constructor ( + private route: ActivatedRoute, + private postPopupService: PostPopupService + ) {} + + ngOnInit() { + this.routeSub = this.route.params.subscribe(params => { + if ( params['id'] ) { + this.modalRef = this.postPopupService + .open(PostDialogComponent, params['id']); + } else { + this.modalRef = this.postPopupService + .open(PostDialogComponent); + } + + }); + } + + ngOnDestroy() { + this.routeSub.unsubscribe(); + } +} diff --git a/jhipster/src/main/webapp/app/entities/post/post-popup.service.ts b/jhipster/src/main/webapp/app/entities/post/post-popup.service.ts new file mode 100644 index 0000000000..42ea731e07 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post-popup.service.ts @@ -0,0 +1,50 @@ +import { Injectable, Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { Post } from './post.model'; +import { PostService } from './post.service'; +@Injectable() +export class PostPopupService { + private isOpen = false; + constructor ( + private modalService: NgbModal, + private router: Router, + private postService: PostService + + ) {} + + open (component: Component, id?: number | any): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + + if (id) { + this.postService.find(id).subscribe(post => { + if (post.creationDate) { + post.creationDate = { + year: post.creationDate.getFullYear(), + month: post.creationDate.getMonth() + 1, + day: post.creationDate.getDate() + }; + } + this.postModalRef(component, post); + }); + } else { + return this.postModalRef(component, new Post()); + } + } + + postModalRef(component: Component, post: Post): NgbModalRef { + let modalRef = this.modalService.open(component, { size: 'lg', backdrop: 'static'}); + modalRef.componentInstance.post = post; + modalRef.result.then(result => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }, (reason) => { + this.router.navigate([{ outlets: { popup: null }}], { replaceUrl: true }); + this.isOpen = false; + }); + return modalRef; + } +} diff --git a/jhipster/src/main/webapp/app/entities/post/post.component.html b/jhipster/src/main/webapp/app/entities/post/post.component.html new file mode 100644 index 0000000000..cf17c4e6dc --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.component.html @@ -0,0 +1,64 @@ +
+

+ Posts + +

+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
ID Title Content Creation Date Creator
{{post.id}}{{post.title}}{{post.content}}{{post.creationDate | date:'mediumDate'}} + {{post.creator?.login}} + +
+ + + +
+
+
+
diff --git a/jhipster/src/main/webapp/app/entities/post/post.component.ts b/jhipster/src/main/webapp/app/entities/post/post.component.ts new file mode 100644 index 0000000000..e8401a48c7 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.component.ts @@ -0,0 +1,110 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Response } from '@angular/http'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subscription } from 'rxjs/Rx'; +import { EventManager, ParseLinks, PaginationUtil, JhiLanguageService, AlertService } from 'ng-jhipster'; + +import { Post } from './post.model'; +import { PostService } from './post.service'; +import { ITEMS_PER_PAGE, Principal } from '../../shared'; +import { PaginationConfig } from '../../blocks/config/uib-pagination.config'; + +@Component({ + selector: 'jhi-post', + templateUrl: './post.component.html' +}) +export class PostComponent implements OnInit, OnDestroy { + + posts: Post[]; + currentAccount: any; + eventSubscriber: Subscription; + itemsPerPage: number; + links: any; + page: any; + predicate: any; + queryCount: any; + reverse: any; + totalItems: number; + + constructor( + private jhiLanguageService: JhiLanguageService, + private postService: PostService, + private alertService: AlertService, + private eventManager: EventManager, + private parseLinks: ParseLinks, + private principal: Principal + ) { + this.posts = []; + this.itemsPerPage = ITEMS_PER_PAGE; + this.page = 0; + this.links = { + last: 0 + }; + this.predicate = 'id'; + this.reverse = true; + this.jhiLanguageService.setLocations(['post']); + } + + loadAll () { + this.postService.query({ + page: this.page, + size: this.itemsPerPage, + sort: this.sort() + }).subscribe( + (res: Response) => this.onSuccess(res.json(), res.headers), + (res: Response) => this.onError(res.json()) + ); + } + + reset () { + this.page = 0; + this.posts = []; + this.loadAll(); + } + + loadPage(page) { + this.page = page; + this.loadAll(); + } + ngOnInit() { + this.loadAll(); + this.principal.identity().then((account) => { + this.currentAccount = account; + }); + this.registerChangeInPosts(); + } + + ngOnDestroy() { + this.eventManager.destroy(this.eventSubscriber); + } + + trackId (index: number, item: Post) { + return item.id; + } + + + + registerChangeInPosts() { + this.eventSubscriber = this.eventManager.subscribe('postListModification', (response) => this.reset()); + } + + sort () { + let result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')]; + if (this.predicate !== 'id') { + result.push('id'); + } + return result; + } + + private onSuccess(data, headers) { + this.links = this.parseLinks.parse(headers.get('link')); + this.totalItems = headers.get('X-Total-Count'); + for (let i = 0; i < data.length; i++) { + this.posts.push(data[i]); + } + } + + private onError (error) { + this.alertService.error(error.message, null, null); + } +} diff --git a/jhipster/src/main/webapp/app/entities/post/post.model.ts b/jhipster/src/main/webapp/app/entities/post/post.model.ts new file mode 100644 index 0000000000..454f7e75f8 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.model.ts @@ -0,0 +1,11 @@ +import { User } from '../../shared'; +export class Post { + constructor( + public id?: number, + public title?: string, + public content?: string, + public creationDate?: any, + public creator?: User, + ) { + } +} diff --git a/jhipster/src/main/webapp/app/entities/post/post.module.ts b/jhipster/src/main/webapp/app/entities/post/post.module.ts new file mode 100644 index 0000000000..53ba982c02 --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.module.ts @@ -0,0 +1,52 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BaeldungSharedModule } from '../../shared'; +import { BaeldungAdminModule } from '../../admin/admin.module'; + +import { + PostService, + PostPopupService, + PostComponent, + PostDetailComponent, + PostDialogComponent, + PostPopupComponent, + PostDeletePopupComponent, + PostDeleteDialogComponent, + postRoute, + postPopupRoute, +} from './'; + +let ENTITY_STATES = [ + ...postRoute, + ...postPopupRoute, +]; + +@NgModule({ + imports: [ + BaeldungSharedModule, + BaeldungAdminModule, + RouterModule.forRoot(ENTITY_STATES, { useHash: true }) + ], + declarations: [ + PostComponent, + PostDetailComponent, + PostDialogComponent, + PostDeleteDialogComponent, + PostPopupComponent, + PostDeletePopupComponent, + ], + entryComponents: [ + PostComponent, + PostDialogComponent, + PostPopupComponent, + PostDeleteDialogComponent, + PostDeletePopupComponent, + ], + providers: [ + PostService, + PostPopupService, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungPostModule {} diff --git a/jhipster/src/main/webapp/app/entities/post/post.route.ts b/jhipster/src/main/webapp/app/entities/post/post.route.ts new file mode 100644 index 0000000000..27b23bdc0d --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.route.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { PaginationUtil } from 'ng-jhipster'; + +import { PostComponent } from './post.component'; +import { PostDetailComponent } from './post-detail.component'; +import { PostPopupComponent } from './post-dialog.component'; +import { PostDeletePopupComponent } from './post-delete-dialog.component'; + +import { Principal } from '../../shared'; + + +export const postRoute: Routes = [ + { + path: 'post', + component: PostComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.post.home.title' + } + }, { + path: 'post/:id', + component: PostDetailComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.post.home.title' + } + } +]; + +export const postPopupRoute: Routes = [ + { + path: 'post-new', + component: PostPopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.post.home.title' + }, + outlet: 'popup' + }, + { + path: 'post/:id/edit', + component: PostPopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.post.home.title' + }, + outlet: 'popup' + }, + { + path: 'post/:id/delete', + component: PostDeletePopupComponent, + data: { + authorities: ['ROLE_USER'], + pageTitle: 'baeldungApp.post.home.title' + }, + outlet: 'popup' + } +]; diff --git a/jhipster/src/main/webapp/app/entities/post/post.service.ts b/jhipster/src/main/webapp/app/entities/post/post.service.ts new file mode 100644 index 0000000000..7f7ee969fe --- /dev/null +++ b/jhipster/src/main/webapp/app/entities/post/post.service.ts @@ -0,0 +1,78 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, URLSearchParams, BaseRequestOptions } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import { Post } from './post.model'; +import { DateUtils } from 'ng-jhipster'; +@Injectable() +export class PostService { + + private resourceUrl = 'api/posts'; + + constructor(private http: Http, private dateUtils: DateUtils) { } + + create(post: Post): Observable { + let copy: Post = Object.assign({}, post); + copy.creationDate = this.dateUtils + .convertLocalDateToServer(post.creationDate); + return this.http.post(this.resourceUrl, copy).map((res: Response) => { + return res.json(); + }); + } + + update(post: Post): Observable { + let copy: Post = Object.assign({}, post); + copy.creationDate = this.dateUtils + .convertLocalDateToServer(post.creationDate); + return this.http.put(this.resourceUrl, copy).map((res: Response) => { + return res.json(); + }); + } + + find(id: number): Observable { + return this.http.get(`${this.resourceUrl}/${id}`).map((res: Response) => { + let jsonResponse = res.json(); + jsonResponse.creationDate = this.dateUtils + .convertLocalDateFromServer(jsonResponse.creationDate); + return jsonResponse; + }); + } + + query(req?: any): Observable { + let options = this.createRequestOption(req); + return this.http.get(this.resourceUrl, options) + .map((res: any) => this.convertResponse(res)) + ; + } + + delete(id: number): Observable { + return this.http.delete(`${this.resourceUrl}/${id}`); + } + + + private convertResponse(res: any): any { + let jsonResponse = res.json(); + for (let i = 0; i < jsonResponse.length; i++) { + jsonResponse[i].creationDate = this.dateUtils + .convertLocalDateFromServer(jsonResponse[i].creationDate); + } + res._body = jsonResponse; + return res; + } + + private createRequestOption(req?: any): BaseRequestOptions { + let options: BaseRequestOptions = new BaseRequestOptions(); + if (req) { + let params: URLSearchParams = new URLSearchParams(); + params.set('page', req.page); + params.set('size', req.size); + if (req.sort) { + params.paramsMap.set('sort', req.sort); + } + params.set('query', req.query); + + options.search = params; + } + return options; + } +} diff --git a/jhipster/src/main/webapp/app/home/home.component.html b/jhipster/src/main/webapp/app/home/home.component.html new file mode 100644 index 0000000000..4c0197228c --- /dev/null +++ b/jhipster/src/main/webapp/app/home/home.component.html @@ -0,0 +1,42 @@ +
+
+ +
+
+

Welcome, Java Hipster!

+

This is your homepage

+ +
+
+ You are logged in as user "{{account.login}}". +
+ +
+ If you want to + sign in, you can try the default accounts:
- Administrator (login="admin" and password="admin")
- User (login="user" and password="user").
+
+ +
+ You don't have an account yet? + Register a new account +
+
+ +

+ If you have any question on JHipster: +

+ + + +

+ If you like JHipster, don't forget to give us a star on Github! +

+
+
diff --git a/jhipster/src/main/webapp/app/home/home.component.ts b/jhipster/src/main/webapp/app/home/home.component.ts new file mode 100644 index 0000000000..b16838377e --- /dev/null +++ b/jhipster/src/main/webapp/app/home/home.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit } from '@angular/core'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { EventManager, JhiLanguageService } from 'ng-jhipster'; + +import { Account, LoginModalService, Principal } from '../shared'; + +@Component({ + selector: 'jhi-home', + templateUrl: './home.component.html', + styleUrls: [ + 'home.scss' + ] + +}) +export class HomeComponent implements OnInit { + account: Account; + modalRef: NgbModalRef; + + constructor( + private jhiLanguageService: JhiLanguageService, + private principal: Principal, + private loginModalService: LoginModalService, + private eventManager: EventManager + ) { + this.jhiLanguageService.setLocations(['home']); + } + + ngOnInit() { + this.principal.identity().then((account) => { + this.account = account; + }); + this.registerAuthenticationSuccess(); + } + + registerAuthenticationSuccess() { + this.eventManager.subscribe('authenticationSuccess', (message) => { + this.principal.identity().then((account) => { + this.account = account; + }); + }); + } + + isAuthenticated() { + return this.principal.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } +} diff --git a/jhipster/src/main/webapp/app/home/home.module.ts b/jhipster/src/main/webapp/app/home/home.module.ts new file mode 100644 index 0000000000..172c605249 --- /dev/null +++ b/jhipster/src/main/webapp/app/home/home.module.ts @@ -0,0 +1,23 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { BaeldungSharedModule } from '../shared'; + +import { HOME_ROUTE, HomeComponent } from './'; + + +@NgModule({ + imports: [ + BaeldungSharedModule, + RouterModule.forRoot([ HOME_ROUTE ], { useHash: true }) + ], + declarations: [ + HomeComponent, + ], + entryComponents: [ + ], + providers: [ + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class BaeldungHomeModule {} diff --git a/jhipster/src/main/webapp/app/home/home.route.ts b/jhipster/src/main/webapp/app/home/home.route.ts new file mode 100644 index 0000000000..cba14bf0c6 --- /dev/null +++ b/jhipster/src/main/webapp/app/home/home.route.ts @@ -0,0 +1,14 @@ +import { Route } from '@angular/router'; + +import { UserRouteAccessService } from '../shared'; +import { HomeComponent } from './'; + +export const HOME_ROUTE: Route = { + path: '', + component: HomeComponent, + data: { + authorities: [], + pageTitle: 'home.title' + }, + canActivate: [UserRouteAccessService] +}; diff --git a/jhipster/src/main/webapp/app/home/home.scss b/jhipster/src/main/webapp/app/home/home.scss new file mode 100644 index 0000000000..578787b1c9 --- /dev/null +++ b/jhipster/src/main/webapp/app/home/home.scss @@ -0,0 +1,26 @@ + +/* ========================================================================== +Main page styles +========================================================================== */ + +.hipster { + display: inline-block; + width: 347px; + height: 497px; + background: url("../../content/images/hipster.png") no-repeat center top; + background-size: contain; +} + +/* wait autoprefixer update to allow simple generation of high pixel density media query */ +@media +only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and ( min--moz-device-pixel-ratio: 2), +only screen and ( -o-min-device-pixel-ratio: 2/1), +only screen and ( min-device-pixel-ratio: 2), +only screen and ( min-resolution: 192dpi), +only screen and ( min-resolution: 2dppx) { + .hipster { + background: url("../../content/images/hipster2x.png") no-repeat center top; + background-size: contain; + } +} diff --git a/jhipster/src/main/webapp/app/home/index.ts b/jhipster/src/main/webapp/app/home/index.ts new file mode 100644 index 0000000000..d76285b277 --- /dev/null +++ b/jhipster/src/main/webapp/app/home/index.ts @@ -0,0 +1,3 @@ +export * from './home.component'; +export * from './home.route'; +export * from './home.module'; diff --git a/jhipster/src/main/webapp/app/layouts/error/error.component.html b/jhipster/src/main/webapp/app/layouts/error/error.component.html new file mode 100644 index 0000000000..92fe2f1512 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/error/error.component.html @@ -0,0 +1,17 @@ +
+
+
+ +
+
+

Error Page!

+ +
+
{{errorMessage}} +
+
+
You are not authorized to access the page. +
+
+
+
diff --git a/jhipster/src/main/webapp/app/layouts/error/error.component.ts b/jhipster/src/main/webapp/app/layouts/error/error.component.ts new file mode 100644 index 0000000000..983809f541 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/error/error.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +@Component({ + selector: 'jhi-error', + templateUrl: './error.component.html' +}) +export class ErrorComponent implements OnInit { + errorMessage: string; + error403: boolean; + + constructor( + private jhiLanguageService: JhiLanguageService + ) { + this.jhiLanguageService.setLocations(['error']); + } + + ngOnInit() { + } +} diff --git a/jhipster/src/main/webapp/app/layouts/error/error.route.ts b/jhipster/src/main/webapp/app/layouts/error/error.route.ts new file mode 100644 index 0000000000..5f6085076c --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/error/error.route.ts @@ -0,0 +1,25 @@ +import { Routes } from '@angular/router'; + +import { UserRouteAccessService } from '../../shared'; +import { ErrorComponent } from './error.component'; + +export const errorRoute: Routes = [ + { + path: 'error', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'error.title' + }, + canActivate: [UserRouteAccessService] + }, + { + path: 'accessdenied', + component: ErrorComponent, + data: { + authorities: [], + pageTitle: 'error.title' + }, + canActivate: [UserRouteAccessService] + } +]; diff --git a/jhipster/src/main/webapp/app/layouts/footer/footer.component.html b/jhipster/src/main/webapp/app/layouts/footer/footer.component.html new file mode 100644 index 0000000000..4e4fda05bf --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/footer/footer.component.html @@ -0,0 +1,4 @@ + + diff --git a/jhipster/src/main/webapp/app/layouts/footer/footer.component.ts b/jhipster/src/main/webapp/app/layouts/footer/footer.component.ts new file mode 100644 index 0000000000..37da8bca75 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/footer/footer.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'jhi-footer', + templateUrl: './footer.component.html' +}) +export class FooterComponent {} diff --git a/jhipster/src/main/webapp/app/layouts/index.ts b/jhipster/src/main/webapp/app/layouts/index.ts new file mode 100644 index 0000000000..f25305a0ac --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/index.ts @@ -0,0 +1,10 @@ +export * from './error/error.component'; +export * from './error/error.route'; +export * from './main/main.component'; +export * from './footer/footer.component'; +export * from './navbar/navbar.component'; +export * from './navbar/active-menu.directive'; +export * from './profiles/page-ribbon.component'; +export * from './profiles/profile.service'; +export * from './profiles/profile-info.model'; +export * from './layout-routing.module'; diff --git a/jhipster/src/main/webapp/app/layouts/layout-routing.module.ts b/jhipster/src/main/webapp/app/layouts/layout-routing.module.ts new file mode 100644 index 0000000000..8edbdff26c --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/layout-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes, Resolve } from '@angular/router'; + +import { navbarRoute } from '../app.route'; +import { errorRoute } from './'; + +let LAYOUT_ROUTES = [ + navbarRoute, + ...errorRoute +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(LAYOUT_ROUTES, { useHash: true }) + ], + exports: [ + RouterModule + ] +}) +export class LayoutRoutingModule {} diff --git a/jhipster/src/main/webapp/app/layouts/main/main.component.html b/jhipster/src/main/webapp/app/layouts/main/main.component.html new file mode 100644 index 0000000000..5bcd12ab0b --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/main/main.component.html @@ -0,0 +1,11 @@ + +
+ +
+
+
+ + +
+ +
diff --git a/jhipster/src/main/webapp/app/layouts/main/main.component.ts b/jhipster/src/main/webapp/app/layouts/main/main.component.ts new file mode 100644 index 0000000000..c5982f60ca --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/main/main.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit } from '@angular/core'; +import { Router, ActivatedRouteSnapshot, NavigationEnd, RoutesRecognized } from '@angular/router'; + +import { JhiLanguageHelper, StateStorageService } from '../../shared'; + +@Component({ + selector: 'jhi-main', + templateUrl: './main.component.html' +}) +export class JhiMainComponent implements OnInit { + + constructor( + private jhiLanguageHelper: JhiLanguageHelper, + private router: Router, + private $storageService: StateStorageService, + ) {} + + private getPageTitle(routeSnapshot: ActivatedRouteSnapshot) { + let title: string = (routeSnapshot.data && routeSnapshot.data['pageTitle']) ? routeSnapshot.data['pageTitle'] : 'baeldungApp'; + if (routeSnapshot.firstChild) { + title = this.getPageTitle(routeSnapshot.firstChild) || title; + } + return title; + } + + ngOnInit() { + this.router.events.subscribe((event) => { + if (event instanceof NavigationEnd) { + this.jhiLanguageHelper.updateTitle(this.getPageTitle(this.router.routerState.snapshot.root)); + } + if (event instanceof RoutesRecognized) { + let params = {}; + let destinationData = {}; + let destinationName = ''; + let destinationEvent = event.state.root.firstChild.children[0]; + if (destinationEvent !== undefined) { + params = destinationEvent.params; + destinationData = destinationEvent.data; + destinationName = destinationEvent.url[0].path; + } + let from = {name: this.router.url.slice(1)}; + let destination = {name: destinationName, data: destinationData}; + this.$storageService.storeDestinationState(destination, params, from); + } + }); + } +} diff --git a/jhipster/src/main/webapp/app/layouts/navbar/active-menu.directive.ts b/jhipster/src/main/webapp/app/layouts/navbar/active-menu.directive.ts new file mode 100644 index 0000000000..87275c9d57 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/navbar/active-menu.directive.ts @@ -0,0 +1,26 @@ +import { Directive, OnInit, ElementRef, Renderer, Input} from '@angular/core'; +import { TranslateService, LangChangeEvent } from 'ng2-translate'; + +@Directive({ + selector: '[jhiActiveMenu]' +}) +export class ActiveMenuDirective implements OnInit { + @Input() jhiActiveMenu: string; + + constructor(private el: ElementRef, private renderer: Renderer, private translateService: TranslateService) {} + + ngOnInit() { + this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { + this.updateActiveFlag(event.lang); + }); + this.updateActiveFlag(this.translateService.currentLang); + } + + updateActiveFlag(selectedLanguage) { + if (this.jhiActiveMenu === selectedLanguage) { + this.renderer.setElementClass(this.el.nativeElement, 'active', true); + } else { + this.renderer.setElementClass(this.el.nativeElement, 'active', false); + } + } +} diff --git a/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.html b/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.html new file mode 100644 index 0000000000..07b7abb25c --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -0,0 +1,168 @@ + diff --git a/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.ts b/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.ts new file mode 100644 index 0000000000..8f58bfebd9 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/navbar/navbar.component.ts @@ -0,0 +1,81 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { ProfileService } from '../profiles/profile.service'; // FIXME barrel doesnt work here +import { JhiLanguageHelper, Principal, LoginModalService, LoginService } from '../../shared'; + +import { VERSION, DEBUG_INFO_ENABLED } from '../../app.constants'; + +@Component({ + selector: 'jhi-navbar', + templateUrl: './navbar.component.html', + styleUrls: [ + 'navbar.scss' + ] +}) +export class NavbarComponent implements OnInit { + + inProduction: boolean; + isNavbarCollapsed: boolean; + languages: any[]; + swaggerEnabled: boolean; + modalRef: NgbModalRef; + version: string; + + constructor( + private loginService: LoginService, + private languageHelper: JhiLanguageHelper, + private languageService: JhiLanguageService, + private principal: Principal, + private loginModalService: LoginModalService, + private profileService: ProfileService, + private router: Router + ) { + this.version = DEBUG_INFO_ENABLED ? 'v' + VERSION : ''; + this.isNavbarCollapsed = true; + this.languageService.addLocation('home'); + } + + ngOnInit() { + this.languageHelper.getAll().then((languages) => { + this.languages = languages; + }); + + this.profileService.getProfileInfo().subscribe(profileInfo => { + this.inProduction = profileInfo.inProduction; + this.swaggerEnabled = profileInfo.swaggerEnabled; + }); + } + + changeLanguage(languageKey: string) { + this.languageService.changeLanguage(languageKey); + } + + collapseNavbar() { + this.isNavbarCollapsed = true; + } + + isAuthenticated() { + return this.principal.isAuthenticated(); + } + + login() { + this.modalRef = this.loginModalService.open(); + } + + logout() { + this.collapseNavbar(); + this.loginService.logout(); + this.router.navigate(['']); + } + + toggleNavbar() { + this.isNavbarCollapsed = !this.isNavbarCollapsed; + } + + getImageUrl() { + return this.isAuthenticated() ? this.principal.getImageUrl() : null; + } +} diff --git a/jhipster/src/main/webapp/app/layouts/navbar/navbar.scss b/jhipster/src/main/webapp/app/layouts/navbar/navbar.scss new file mode 100644 index 0000000000..d48d609543 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/navbar/navbar.scss @@ -0,0 +1,70 @@ + +/* ========================================================================== +Navbar +========================================================================== */ +.navbar-version { + font-size: 10px; + color: #ccc +} + +.jh-navbar { + background-color: #353d47; + padding: .2em 1em; + .profile-image { + margin: -10px 0px; + height: 40px; + width: 40px; + border-radius: 50%; + } + .dropdown-item.active, .dropdown-item.active:focus, .dropdown-item.active:hover { + background-color: #353d47; + } + .dropdown-toggle::after { + margin-left: 0.15em; + } + ul.navbar-nav { + padding: 0.5em; + .nav-item { + margin-left: 1.5rem; + } + } + a.nav-link { + font-weight: 400; + } + .jh-navbar-toggler { + color: #ccc; + font-size: 1.5em; + padding: 10px; + &:hover { + color: #fff; + } + } +} + +@media screen and (max-width: 992px) { + .jh-logo-container { + width: 100%; + } +} + +.navbar-title { + display: inline-block; + vertical-align: middle; +} + +/* ========================================================================== +Logo styles +========================================================================== */ +.navbar-brand { + &.logo { + padding: 5px 15px; + .logo-img { + height: 45px; + width: 70px; + display: inline-block; + vertical-align: middle; + background: url("../../../content/images/logo-jhipster.png") no-repeat center center; + background-size: contain; + } + } +} diff --git a/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts b/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts new file mode 100644 index 0000000000..f7ba492f66 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { ProfileService } from './profile.service'; +import { ProfileInfo } from './profile-info.model'; + +@Component({ + selector: 'jhi-page-ribbon', + template: ``, + styleUrls: [ + 'page-ribbon.scss' + ] +}) +export class PageRibbonComponent implements OnInit { + + profileInfo: ProfileInfo; + ribbonEnv: string; + + constructor(private profileService: ProfileService) {} + + ngOnInit() { + this.profileService.getProfileInfo().subscribe(profileInfo => { + this.profileInfo = profileInfo; + this.ribbonEnv = profileInfo.ribbonEnv; + }); + } +} diff --git a/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.scss b/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.scss new file mode 100644 index 0000000000..5efd11c03e --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/profiles/page-ribbon.scss @@ -0,0 +1,32 @@ + +/* ========================================================================== +Developement Ribbon +========================================================================== */ +.ribbon { + background-color: rgba(170, 0, 0, 0.5); + left: -3.5em; + moz-transform: rotate(-45deg); + ms-transform: rotate(-45deg); + o-transform: rotate(-45deg); + webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + overflow: hidden; + position: absolute; + top: 40px; + white-space: nowrap; + width: 15em; + z-index: 9999; + pointer-events: none; + opacity: 0.75; + a { + color: #fff; + display: block; + font-weight: 400; + margin: 1px 0; + padding: 10px 50px; + text-align: center; + text-decoration: none; + text-shadow: 0 0 5px #444; + pointer-events: none; + } +} diff --git a/jhipster/src/main/webapp/app/layouts/profiles/profile-info.model.ts b/jhipster/src/main/webapp/app/layouts/profiles/profile-info.model.ts new file mode 100644 index 0000000000..f1adc52c7b --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/profiles/profile-info.model.ts @@ -0,0 +1,6 @@ +export class ProfileInfo { + activeProfiles: string[]; + ribbonEnv: string; + inProduction: boolean; + swaggerEnabled: boolean; +} diff --git a/jhipster/src/main/webapp/app/layouts/profiles/profile.service.ts b/jhipster/src/main/webapp/app/layouts/profiles/profile.service.ts new file mode 100644 index 0000000000..347b84d8e5 --- /dev/null +++ b/jhipster/src/main/webapp/app/layouts/profiles/profile.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import { ProfileInfo } from './profile-info.model'; + +@Injectable() +export class ProfileService { + + private profileInfoUrl = 'api/profile-info'; + + constructor(private http: Http) { } + + getProfileInfo(): Observable { + return this.http.get(this.profileInfoUrl) + .map((res: Response) => { + let data = res.json(); + let pi = new ProfileInfo(); + pi.activeProfiles = data.activeProfiles; + pi.ribbonEnv = data.ribbonEnv; + pi.inProduction = data.activeProfiles.indexOf('prod') !== -1; + pi.swaggerEnabled = data.activeProfiles.indexOf('swagger') !== -1; + return pi; + }); + } +} diff --git a/jhipster/src/main/webapp/app/polyfills.ts b/jhipster/src/main/webapp/app/polyfills.ts new file mode 100644 index 0000000000..0771ba0b72 --- /dev/null +++ b/jhipster/src/main/webapp/app/polyfills.ts @@ -0,0 +1,3 @@ +/* tslint:disable */ +import 'reflect-metadata/Reflect'; +import 'zone.js/dist/zone'; diff --git a/jhipster/src/main/webapp/app/shared/alert/alert-error.component.ts b/jhipster/src/main/webapp/app/shared/alert/alert-error.component.ts new file mode 100644 index 0000000000..e9e3e2b7a0 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/alert/alert-error.component.ts @@ -0,0 +1,101 @@ +import { Component, OnDestroy } from '@angular/core'; +import { TranslateService } from 'ng2-translate'; +import { EventManager, AlertService } from 'ng-jhipster'; +import { Subscription } from 'rxjs/Rx'; + +@Component({ + selector: 'jhi-alert-error', + template: ` + ` +}) +export class JhiAlertErrorComponent implements OnDestroy { + + alerts: any[]; + cleanHttpErrorListener: Subscription; + + constructor(private alertService: AlertService, private eventManager: EventManager, private translateService: TranslateService) { + this.alerts = []; + + this.cleanHttpErrorListener = eventManager.subscribe('baeldungApp.httpError', (response) => { + let i; + let httpResponse = response.content; + switch (httpResponse.status) { + // connection refused, server not reachable + case 0: + this.addErrorAlert('Server not reachable', 'error.server.not.reachable'); + break; + + case 400: + let arr = Array.from(httpResponse.headers._headers); + let headers = []; + for (i = 0; i < arr.length; i++) { + if (arr[i][0].endsWith('app-error') || arr[i][0].endsWith('app-params')) { + headers.push(arr[i][0]); + } + } + headers.sort(); + let errorHeader = httpResponse.headers.get(headers[0]); + let entityKey = httpResponse.headers.get(headers[1]); + if (errorHeader) { + let entityName = translateService.instant('global.menu.entities.' + entityKey); + this.addErrorAlert(errorHeader, errorHeader, {entityName: entityName}); + } else if (httpResponse.text() !== '' && httpResponse.json() && httpResponse.json().fieldErrors) { + let fieldErrors = httpResponse.json().fieldErrors; + for (i = 0; i < fieldErrors.length; i++) { + let fieldError = fieldErrors[i]; + // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it + let convertedField = fieldError.field.replace(/\[\d*\]/g, '[]'); + let fieldName = translateService.instant('baeldungApp.' + + fieldError.objectName + '.' + convertedField); + this.addErrorAlert( + 'Field ' + fieldName + ' cannot be empty', 'error.' + fieldError.message, {fieldName: fieldName}); + } + } else if (httpResponse.text() !== '' && httpResponse.json() && httpResponse.json().message) { + this.addErrorAlert(httpResponse.json().message, httpResponse.json().message, httpResponse.json()); + } else { + this.addErrorAlert(httpResponse.text()); + } + break; + + case 404: + this.addErrorAlert('Not found', 'error.url.not.found'); + break; + + default: + if (httpResponse.text() !== '' && httpResponse.json() && httpResponse.json().message) { + this.addErrorAlert(httpResponse.json().message); + } else { + this.addErrorAlert(JSON.stringify(httpResponse)); // Fixme find a way to parse httpResponse + } + } + }); + } + + ngOnDestroy() { + if (this.cleanHttpErrorListener !== undefined && this.cleanHttpErrorListener !== null) { + this.eventManager.destroy(this.cleanHttpErrorListener); + this.alerts = []; + } + } + + addErrorAlert (message, key?, data?) { + key = key && key !== null ? key : message; + this.alerts.push( + this.alertService.addAlert( + { + type: 'danger', + msg: key, + params: data, + timeout: 5000, + toast: this.alertService.isToast(), + scoped: true + }, + this.alerts + ) + ); + } +} diff --git a/jhipster/src/main/webapp/app/shared/alert/alert.component.ts b/jhipster/src/main/webapp/app/shared/alert/alert.component.ts new file mode 100644 index 0000000000..b8aa418ac5 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/alert/alert.component.ts @@ -0,0 +1,26 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AlertService } from 'ng-jhipster'; + +@Component({ + selector: 'jhi-alert', + template: ` + ` +}) +export class JhiAlertComponent implements OnInit, OnDestroy { + alerts: any[]; + + constructor(private alertService: AlertService) { } + + ngOnInit() { + this.alerts = this.alertService.get(); + } + + ngOnDestroy() { + this.alerts = []; + } + +} diff --git a/jhipster/src/main/webapp/app/shared/auth/account.service.ts b/jhipster/src/main/webapp/app/shared/auth/account.service.ts new file mode 100644 index 0000000000..6d21943d49 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/account.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +@Injectable() +export class AccountService { + constructor(private http: Http) { } + + get(): Observable { + return this.http.get('api/account').map((res: Response) => res.json()); + } + + save(account: any): Observable { + return this.http.post('api/account', account); + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/auth-jwt.service.ts b/jhipster/src/main/webapp/app/shared/auth/auth-jwt.service.ts new file mode 100644 index 0000000000..9be418d175 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/auth-jwt.service.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, Headers, URLSearchParams } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; +import { LocalStorageService, SessionStorageService } from 'ng2-webstorage'; + +@Injectable() +export class AuthServerProvider { + constructor( + private http: Http, + private $localStorage: LocalStorageService, + private $sessionStorage: SessionStorageService + ) {} + + getToken () { + return this.$localStorage.retrieve('authenticationToken') || this.$sessionStorage.retrieve('authenticationToken'); + } + + login (credentials): Observable { + + let data = { + username: credentials.username, + password: credentials.password, + rememberMe: credentials.rememberMe + }; + return this.http.post('api/authenticate', data).map(authenticateSuccess.bind(this)); + + function authenticateSuccess (resp) { + let bearerToken = resp.headers.get('Authorization'); + if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') { + let jwt = bearerToken.slice(7, bearerToken.length); + this.storeAuthenticationToken(jwt, credentials.rememberMe); + return jwt; + } + } + } + + loginWithToken(jwt, rememberMe) { + if (jwt) { + this.storeAuthenticationToken(jwt, rememberMe); + return Promise.resolve(jwt); + } else { + return Promise.reject('auth-jwt-service Promise reject'); // Put appropriate error message here + } + } + + storeAuthenticationToken(jwt, rememberMe) { + if (rememberMe) { + this.$localStorage.store('authenticationToken', jwt); + } else { + this.$sessionStorage.store('authenticationToken', jwt); + } + } + + logout (): Observable { + return new Observable(observer => { + this.$localStorage.clear('authenticationToken'); + this.$sessionStorage.clear('authenticationToken'); + observer.complete(); + }); + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/auth.service.ts b/jhipster/src/main/webapp/app/shared/auth/auth.service.ts new file mode 100644 index 0000000000..9e21fb6737 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/auth.service.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +import { LoginModalService } from '../login/login-modal.service'; +import { Principal } from './principal.service'; +import { StateStorageService } from './state-storage.service'; + +@Injectable() +export class AuthService { + + constructor( + private principal: Principal, + private stateStorageService: StateStorageService, + private loginModalService: LoginModalService, + private router: Router + ) {} + + authorize (force) { + let authReturn = this.principal.identity(force).then(authThen.bind(this)); + + return authReturn; + + function authThen () { + let isAuthenticated = this.principal.isAuthenticated(); + let toStateInfo = this.stateStorageService.getDestinationState().destination; + + // an authenticated user can't access to login and register pages + if (isAuthenticated && (toStateInfo.name === 'register' || toStateInfo.name === 'social-auth')) { + this.router.navigate(['']); + return false; + } + + // recover and clear previousState after external login redirect (e.g. oauth2) + let fromStateInfo = this.stateStorageService.getDestinationState().from; + let previousState = this.stateStorageService.getPreviousState(); + if (isAuthenticated && !fromStateInfo.name && previousState) { + this.stateStorageService.resetPreviousState(); + this.router.navigate([previousState.name], { queryParams: previousState.params }); + return false; + } + + if (toStateInfo.data.authorities && toStateInfo.data.authorities.length > 0) { + return this.principal.hasAnyAuthority(toStateInfo.data.authorities).then(hasAnyAuthority => { + if (!hasAnyAuthority) { + if (isAuthenticated) { + // user is signed in but not authorized for desired state + this.router.navigate(['accessdenied']); + } else { + // user is not authenticated. Show the state they wanted before you + // send them to the login service, so you can return them when you're done + let toStateParamsInfo = this.stateStorageService.getDestinationState().params; + this.stateStorageService.storePreviousState(toStateInfo.name, toStateParamsInfo); + // now, send them to the signin state so they can log in + this.router.navigate(['accessdenied']).then(() => { + this.loginModalService.open(); + }); + } + } + return hasAnyAuthority; + }); + } + return true; + } + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/csrf.service.ts b/jhipster/src/main/webapp/app/shared/auth/csrf.service.ts new file mode 100644 index 0000000000..6f1064112a --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/csrf.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { CookieService } from 'angular2-cookie/core'; + +@Injectable() +export class CSRFService { + + constructor(private cookieService: CookieService) {} + + getCSRF(name?: string) { + name = `${name ? name : 'XSRF-TOKEN'}`; + return this.cookieService.get(name); + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/has-any-authority.directive.ts b/jhipster/src/main/webapp/app/shared/auth/has-any-authority.directive.ts new file mode 100644 index 0000000000..858c105fd5 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/has-any-authority.directive.ts @@ -0,0 +1,42 @@ +import { Directive, ElementRef, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { Principal } from './principal.service'; + +/** + * @whatItDoes Conditionally includes an HTML element if current user has any + * of the authorities passed as the `expression`. + * + * @howToUse + * ``` + * ... + * + * ... + * ``` + */ +@Directive({ + selector: '[jhiHasAnyAuthority]' +}) +export class HasAnyAuthorityDirective { + + private authorities: string[]; + + constructor(private principal: Principal, private templateRef: TemplateRef, private viewContainerRef: ViewContainerRef) { + } + + @Input() + set jhiHasAnyAuthority(value: string|string[]) { + this.authorities = typeof value === 'string' ? [ value ] : value; + this.updateView(); + // Get notified each time authentication state changes. + this.principal.getAuthenticationState().subscribe(identity => this.updateView()); + } + + private updateView(): void { + this.principal.hasAnyAuthority(this.authorities).then(result => { + if (result) { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } else { + this.viewContainerRef.clear(); + } + }); + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/principal.service.ts b/jhipster/src/main/webapp/app/shared/auth/principal.service.ts new file mode 100644 index 0000000000..2c7f05dd56 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/principal.service.ts @@ -0,0 +1,93 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { AccountService } from './account.service'; + +@Injectable() +export class Principal { + private userIdentity: any; + private authenticated = false; + private authenticationState = new Subject(); + + constructor( + private account: AccountService + ) {} + + authenticate (identity) { + this.userIdentity = identity; + this.authenticated = identity !== null; + this.authenticationState.next(this.userIdentity); + } + + hasAnyAuthority (authorities: string[]): Promise { + if (!this.authenticated || !this.userIdentity || !this.userIdentity.authorities) { + return Promise.resolve(false); + } + + for (let i = 0; i < authorities.length; i++) { + if (this.userIdentity.authorities.indexOf(authorities[i]) !== -1) { + return Promise.resolve(true); + } + } + + return Promise.resolve(false); + } + + hasAuthority (authority: string): Promise { + if (!this.authenticated) { + return Promise.resolve(false); + } + + return this.identity().then(id => { + return Promise.resolve(id.authorities && id.authorities.indexOf(authority) !== -1); + }, () => { + return Promise.resolve(false); + }); + } + + identity (force?: boolean): Promise { + if (force === true) { + this.userIdentity = undefined; + } + + // check and see if we have retrieved the userIdentity data from the server. + // if we have, reuse it by immediately resolving + if (this.userIdentity) { + return Promise.resolve(this.userIdentity); + } + + // retrieve the userIdentity data from the server, update the identity object, and then resolve. + return this.account.get().toPromise().then(account => { + if (account) { + this.userIdentity = account; + this.authenticated = true; + } else { + this.userIdentity = null; + this.authenticated = false; + } + this.authenticationState.next(this.userIdentity); + return this.userIdentity; + }).catch(err => { + this.userIdentity = null; + this.authenticated = false; + this.authenticationState.next(this.userIdentity); + return null; + }); + } + + isAuthenticated (): boolean { + return this.authenticated; + } + + isIdentityResolved (): boolean { + return this.userIdentity !== undefined; + } + + getAuthenticationState(): Observable { + return this.authenticationState.asObservable(); + } + + getImageUrl(): String { + return this.isIdentityResolved () ? this.userIdentity.imageUrl : null; + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/state-storage.service.ts b/jhipster/src/main/webapp/app/shared/auth/state-storage.service.ts new file mode 100644 index 0000000000..1fe364b06d --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/state-storage.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { SessionStorageService } from 'ng2-webstorage'; + +@Injectable() +export class StateStorageService { + constructor( + private $sessionStorage: SessionStorageService + ) {} + + getPreviousState() { + return this.$sessionStorage.retrieve('previousState'); + } + + resetPreviousState() { + this.$sessionStorage.clear('previousState'); + } + + storePreviousState(previousStateName, previousStateParams) { + let previousState = { 'name': previousStateName, 'params': previousStateParams }; + this.$sessionStorage.store('previousState', previousState); + } + + getDestinationState() { + return this.$sessionStorage.retrieve('destinationState'); + } + + storeDestinationState(destinationState, destinationStateParams, fromState) { + let destinationInfo = { + 'destination': { + 'name': destinationState.name, + 'data': destinationState.data, + }, + 'params': destinationStateParams, + 'from': { + 'name': fromState.name, + } + }; + this.$sessionStorage.store('destinationState', destinationInfo); + } +} diff --git a/jhipster/src/main/webapp/app/shared/auth/user-route-access-service.ts b/jhipster/src/main/webapp/app/shared/auth/user-route-access-service.ts new file mode 100644 index 0000000000..95eb236672 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/auth/user-route-access-service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, Router, ActivatedRouteSnapshot } from '@angular/router'; + +import { AuthService } from '../'; + +@Injectable() +export class UserRouteAccessService implements CanActivate { + + constructor(private router: Router, private auth: AuthService) { + } + + canActivate(route: ActivatedRouteSnapshot): boolean | Promise { + return this.auth.authorize(false).then( canActivate => canActivate); + } +} diff --git a/jhipster/src/main/webapp/app/shared/constants/pagination.constants.ts b/jhipster/src/main/webapp/app/shared/constants/pagination.constants.ts new file mode 100644 index 0000000000..a148d4579b --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/constants/pagination.constants.ts @@ -0,0 +1 @@ +export const ITEMS_PER_PAGE = 20; diff --git a/jhipster/src/main/webapp/app/shared/index.ts b/jhipster/src/main/webapp/app/shared/index.ts new file mode 100644 index 0000000000..d2687cf884 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/index.ts @@ -0,0 +1,23 @@ +export * from './alert/alert.component'; +export * from './alert/alert-error.component'; +export * from './auth/csrf.service'; +export * from './auth/state-storage.service'; +export * from './auth/account.service'; +export * from './auth/auth-jwt.service'; +export * from './auth/auth.service'; +export * from './auth/principal.service'; +export * from './auth/has-any-authority.directive'; +export * from './language/language.constants'; +export * from './language/language.helper'; +export * from './language/language.pipe'; +export * from './login/login.component'; +export * from './login/login.service'; +export * from './login/login-modal.service'; +export * from './constants/pagination.constants'; +export * from './user/account.model'; +export * from './user/user.model'; +export * from './user/user.service'; +export * from './shared-libs.module'; +export * from './shared-common.module'; +export * from './shared.module'; +export * from './auth/user-route-access-service'; diff --git a/jhipster/src/main/webapp/app/shared/language/language.constants.ts b/jhipster/src/main/webapp/app/shared/language/language.constants.ts new file mode 100644 index 0000000000..2292ef4624 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/language/language.constants.ts @@ -0,0 +1,8 @@ +/* + Languages codes are ISO_639-1 codes, see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + They are written in English to avoid character encoding issues (not a perfect solution) +*/ +export const LANGUAGES: string[] = [ + 'en' + // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array +]; diff --git a/jhipster/src/main/webapp/app/shared/language/language.helper.ts b/jhipster/src/main/webapp/app/shared/language/language.helper.ts new file mode 100644 index 0000000000..d8d609bf0c --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/language/language.helper.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { Router, ActivatedRouteSnapshot } from '@angular/router'; +import { TranslateService, TranslationChangeEvent, LangChangeEvent } from 'ng2-translate/ng2-translate'; + +import { LANGUAGES } from './language.constants'; + +@Injectable() +export class JhiLanguageHelper { + + constructor (private translateService: TranslateService, private titleService: Title, private router: Router) { + this.init(); + } + + getAll(): Promise { + return Promise.resolve(LANGUAGES); + } + + /** + * Update the window title using params in the following + * order: + * 1. titleKey parameter + * 2. $state.$current.data.pageTitle (current state page title) + * 3. 'global.title' + */ + updateTitle(titleKey?: string) { + if (!titleKey) { + titleKey = this.getPageTitle(this.router.routerState.snapshot.root); + } + + this.translateService.get(titleKey).subscribe(title => { + this.titleService.setTitle(title); + }); + } + + private init () { + this.translateService.onTranslationChange.subscribe((event: TranslationChangeEvent) => { + this.updateTitle(); + }); + + this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { + this.updateTitle(); + }); + } + + private getPageTitle(routeSnapshot: ActivatedRouteSnapshot) { + let title: string = (routeSnapshot.data && routeSnapshot.data['pageTitle']) ? routeSnapshot.data['pageTitle'] : 'baeldungApp'; + if (routeSnapshot.firstChild) { + title = this.getPageTitle(routeSnapshot.firstChild) || title; + } + return title; + } +} diff --git a/jhipster/src/main/webapp/app/shared/language/language.pipe.ts b/jhipster/src/main/webapp/app/shared/language/language.pipe.ts new file mode 100644 index 0000000000..d271c8e2c2 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/language/language.pipe.ts @@ -0,0 +1,42 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'findLanguageFromKey'}) +export class FindLanguageFromKeyPipe implements PipeTransform { + private languages: any = { + 'ca': 'Català', + 'cs': 'ÄŒeský', + 'da': 'Dansk', + 'de': 'Deutsch', + 'el': 'Ελληνικά', + 'en': 'English', + 'es': 'Español', + 'et': 'Eesti', + 'fr': 'Français', + 'gl': 'Galego', + 'hu': 'Magyar', + 'hi': 'हिंदी', + 'hy': 'Õ€Õ¡ÕµÕ¥Ö€Õ¥Õ¶', + 'it': 'Italiano', + 'ja': '日本語', + 'ko': '한국어', + 'mr': 'मराठी', + 'nl': 'Nederlands', + 'pl': 'Polski', + 'pt-br': 'Português (Brasil)', + 'pt-pt': 'Português', + 'ro': 'Română', + 'ru': 'РуÑÑкий', + 'sk': 'Slovenský', + 'sr': 'Srpski', + 'sv': 'Svenska', + 'ta': 'தமிழà¯', + 'th': 'ไทย', + 'tr': 'Türkçe', + 'vi': 'Tiếng Việt', + 'zh-cn': '中文(简体)', + 'zh-tw': 'ç¹é«”中文' + }; + transform(lang: string): string { + return this.languages[lang]; + } +} diff --git a/jhipster/src/main/webapp/app/shared/login/login-modal.service.ts b/jhipster/src/main/webapp/app/shared/login/login-modal.service.ts new file mode 100644 index 0000000000..9e435978ea --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/login/login-modal.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; + +import { JhiLoginModalComponent } from './login.component'; + +@Injectable() +export class LoginModalService { + private isOpen = false; + constructor ( + private modalService: NgbModal, + ) {} + + open (): NgbModalRef { + if (this.isOpen) { + return; + } + this.isOpen = true; + let modalRef = this.modalService.open(JhiLoginModalComponent); + modalRef.result.then(result => { + this.isOpen = false; + }, (reason) => { + this.isOpen = false; + }); + return modalRef; + } +} diff --git a/jhipster/src/main/webapp/app/shared/login/login.component.html b/jhipster/src/main/webapp/app/shared/login/login.component.html new file mode 100644 index 0000000000..a6b6b19249 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/login/login.component.html @@ -0,0 +1,46 @@ + + diff --git a/jhipster/src/main/webapp/app/shared/login/login.component.ts b/jhipster/src/main/webapp/app/shared/login/login.component.ts new file mode 100644 index 0000000000..90acbb03ac --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/login/login.component.ts @@ -0,0 +1,90 @@ +import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Router } from '@angular/router'; +import { JhiLanguageService, EventManager } from 'ng-jhipster'; + +import { LoginService } from '../login/login.service'; +import { StateStorageService } from '../auth/state-storage.service'; + +@Component({ + selector: 'jhi-login-modal', + templateUrl: './login.component.html' +}) +export class JhiLoginModalComponent implements OnInit, AfterViewInit { + authenticationError: boolean; + password: string; + rememberMe: boolean; + username: string; + credentials: any; + + constructor( + private eventManager: EventManager, + private languageService: JhiLanguageService, + private loginService: LoginService, + private stateStorageService: StateStorageService, + private elementRef: ElementRef, + private renderer: Renderer, + private router: Router, + public activeModal: NgbActiveModal + ) { + this.credentials = {}; + } + + ngOnInit() { + this.languageService.addLocation('login'); + } + + ngAfterViewInit() { + this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#username'), 'focus', []); + } + + cancel () { + this.credentials = { + username: null, + password: null, + rememberMe: true + }; + this.authenticationError = false; + this.activeModal.dismiss('cancel'); + } + + login () { + this.loginService.login({ + username: this.username, + password: this.password, + rememberMe: this.rememberMe + }).then(() => { + this.authenticationError = false; + this.activeModal.dismiss('login success'); + if (this.router.url === '/register' || (/activate/.test(this.router.url)) || + this.router.url === '/finishReset' || this.router.url === '/requestReset') { + this.router.navigate(['']); + } + + this.eventManager.broadcast({ + name: 'authenticationSuccess', + content: 'Sending Authentication Success' + }); + + // // previousState was set in the authExpiredInterceptor before being redirected to login modal. + // // since login is succesful, go to stored previousState and clear previousState + let previousState = this.stateStorageService.getPreviousState(); + if (previousState) { + this.stateStorageService.resetPreviousState(); + this.router.navigate([previousState.name], { queryParams: previousState.params }); + } + }).catch(() => { + this.authenticationError = true; + }); + } + + register () { + this.activeModal.dismiss('to state register'); + this.router.navigate(['/register']); + } + + requestResetPassword () { + this.activeModal.dismiss('to state requestReset'); + this.router.navigate(['/reset', 'request']); + } +} diff --git a/jhipster/src/main/webapp/app/shared/login/login.service.ts b/jhipster/src/main/webapp/app/shared/login/login.service.ts new file mode 100644 index 0000000000..2235299225 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/login/login.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { JhiLanguageService } from 'ng-jhipster'; + +import { Principal } from '../auth/principal.service'; +import { AuthServerProvider } from '../auth/auth-jwt.service'; + +@Injectable() +export class LoginService { + + constructor ( + private languageService: JhiLanguageService, + private principal: Principal, + private authServerProvider: AuthServerProvider + ) {} + + login (credentials, callback?) { + let cb = callback || function() {}; + + return new Promise((resolve, reject) => { + this.authServerProvider.login(credentials).subscribe(data => { + this.principal.identity(true).then(account => { + // After the login the language will be changed to + // the language selected by the user during his registration + if (account !== null) { + this.languageService.changeLanguage(account.langKey); + } + resolve(data); + }); + return cb(); + }, err => { + this.logout(); + reject(err); + return cb(err); + }); + }); + } + loginWithToken(jwt, rememberMe) { + return this.authServerProvider.loginWithToken(jwt, rememberMe); + } + + logout () { + this.authServerProvider.logout().subscribe(); + this.principal.authenticate(null); + } +} diff --git a/jhipster/src/main/webapp/app/shared/shared-common.module.ts b/jhipster/src/main/webapp/app/shared/shared-common.module.ts new file mode 100644 index 0000000000..6f713e216b --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/shared-common.module.ts @@ -0,0 +1,47 @@ +import { NgModule, Sanitizer } from '@angular/core'; +import { Title } from '@angular/platform-browser'; + +import { TranslateService } from 'ng2-translate'; +import { AlertService } from 'ng-jhipster'; + +import { + BaeldungSharedLibsModule, + JhiLanguageHelper, + FindLanguageFromKeyPipe, + JhiAlertComponent, + JhiAlertErrorComponent +} from './'; + + +export function alertServiceProvider(sanitizer: Sanitizer, translateService: TranslateService) { + // set below to true to make alerts look like toast + let isToast = false; + return new AlertService(sanitizer, isToast, translateService); +} + +@NgModule({ + imports: [ + BaeldungSharedLibsModule + ], + declarations: [ + FindLanguageFromKeyPipe, + JhiAlertComponent, + JhiAlertErrorComponent + ], + providers: [ + JhiLanguageHelper, + { + provide: AlertService, + useFactory: alertServiceProvider, + deps: [Sanitizer, TranslateService] + }, + Title + ], + exports: [ + BaeldungSharedLibsModule, + FindLanguageFromKeyPipe, + JhiAlertComponent, + JhiAlertErrorComponent + ] +}) +export class BaeldungSharedCommonModule {} diff --git a/jhipster/src/main/webapp/app/shared/shared-libs.module.ts b/jhipster/src/main/webapp/app/shared/shared-libs.module.ts new file mode 100644 index 0000000000..0bf10eeaa8 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/shared-libs.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; +import { CommonModule } from '@angular/common'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgJhipsterModule } from 'ng-jhipster'; +import { InfiniteScrollModule } from 'angular2-infinite-scroll'; + +@NgModule({ + imports: [ + NgbModule.forRoot(), + NgJhipsterModule.forRoot({ + i18nEnabled: true, + defaultI18nLang: 'en' + }), + InfiniteScrollModule + ], + exports: [ + FormsModule, + HttpModule, + CommonModule, + NgbModule, + NgJhipsterModule, + InfiniteScrollModule + ] +}) +export class BaeldungSharedLibsModule {} diff --git a/jhipster/src/main/webapp/app/shared/shared.module.ts b/jhipster/src/main/webapp/app/shared/shared.module.ts new file mode 100644 index 0000000000..f7af13852b --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/shared.module.ts @@ -0,0 +1,53 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { DatePipe } from '@angular/common'; + +import { CookieService } from 'angular2-cookie/services/cookies.service'; +import { + BaeldungSharedLibsModule, + BaeldungSharedCommonModule, + CSRFService, + AuthService, + AuthServerProvider, + AccountService, + UserService, + StateStorageService, + LoginService, + LoginModalService, + Principal, + HasAnyAuthorityDirective, + JhiLoginModalComponent +} from './'; + +@NgModule({ + imports: [ + BaeldungSharedLibsModule, + BaeldungSharedCommonModule + ], + declarations: [ + JhiLoginModalComponent, + HasAnyAuthorityDirective + ], + providers: [ + CookieService, + LoginService, + LoginModalService, + AccountService, + StateStorageService, + Principal, + CSRFService, + AuthServerProvider, + AuthService, + UserService, + DatePipe + ], + entryComponents: [JhiLoginModalComponent], + exports: [ + BaeldungSharedCommonModule, + JhiLoginModalComponent, + HasAnyAuthorityDirective, + DatePipe + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + +}) +export class BaeldungSharedModule {} diff --git a/jhipster/src/main/webapp/app/shared/user/account.model.ts b/jhipster/src/main/webapp/app/shared/user/account.model.ts new file mode 100644 index 0000000000..c8b9750760 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/user/account.model.ts @@ -0,0 +1,12 @@ +export class Account { + constructor( + public activated: boolean, + public authorities: string[], + public email: string, + public firstName: string, + public langKey: string, + public lastName: string, + public login: string, + public imageUrl: string + ) { } +} diff --git a/jhipster/src/main/webapp/app/shared/user/user.model.ts b/jhipster/src/main/webapp/app/shared/user/user.model.ts new file mode 100644 index 0000000000..374c3ae0ca --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/user/user.model.ts @@ -0,0 +1,44 @@ +export class User { + public id?: any; + public login?: string; + public firstName?: string; + public lastName?: string; + public email?: string; + public activated?: Boolean; + public langKey?: string; + public authorities?: any[]; + public createdBy?: string; + public createdDate?: Date; + public lastModifiedBy?: string; + public lastModifiedDate?: Date; + public password?: string; + constructor( + id?: any, + login?: string, + firstName?: string, + lastName?: string, + email?: string, + activated?: Boolean, + langKey?: string, + authorities?: any[], + createdBy?: string, + createdDate?: Date, + lastModifiedBy?: string, + lastModifiedDate?: Date, + password?: string + ) { + this.id = id ? id : null; + this.login = login ? login : null; + this.firstName = firstName ? firstName : null; + this.lastName = lastName ? lastName : null; + this.email = email ? email : null; + this.activated = activated ? activated : false; + this.langKey = langKey ? langKey : null; + this.authorities = authorities ? authorities : null; + this.createdBy = createdBy ? createdBy : null; + this.createdDate = createdDate ? createdDate : null; + this.lastModifiedBy = lastModifiedBy ? lastModifiedBy : null; + this.lastModifiedDate = lastModifiedDate ? lastModifiedDate : null; + this.password = password ? password : null; + } +} diff --git a/jhipster/src/main/webapp/app/shared/user/user.service.ts b/jhipster/src/main/webapp/app/shared/user/user.service.ts new file mode 100644 index 0000000000..b0e1121215 --- /dev/null +++ b/jhipster/src/main/webapp/app/shared/user/user.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { Http, Response, URLSearchParams } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import { User } from './user.model'; + +@Injectable() +export class UserService { + private resourceUrl = 'api/users'; + + constructor(private http: Http) { } + + create(user: User): Observable { + return this.http.post(this.resourceUrl, user); + } + + update(user: User): Observable { + return this.http.put(this.resourceUrl, user); + } + + find(login: string): Observable { + return this.http.get(`${this.resourceUrl}/${login}`).map((res: Response) => res.json()); + } + + query(req?: any): Observable { + let params: URLSearchParams = new URLSearchParams(); + if (req) { + params.set('page', req.page); + params.set('size', req.size); + if (req.sort) { + params.paramsMap.set('sort', req.sort); + } + } + + let options = { + search: params + }; + + return this.http.get(this.resourceUrl, options); + } + + delete(login: string): Observable { + return this.http.delete(`${this.resourceUrl}/${login}`); + } +} diff --git a/jhipster/src/main/webapp/app/vendor.ts b/jhipster/src/main/webapp/app/vendor.ts new file mode 100644 index 0000000000..f9ccfd5b00 --- /dev/null +++ b/jhipster/src/main/webapp/app/vendor.ts @@ -0,0 +1,3 @@ +/* after changing this file run 'npm install' or 'npm run webpack:build' */ +/* tslint:disable */ +import '../content/scss/vendor.scss'; diff --git a/jhipster/src/main/webapp/content/images/hipster.png b/jhipster/src/main/webapp/content/images/hipster.png new file mode 100644 index 0000000000000000000000000000000000000000..141778d482528a8c6636d56d6683f74b21a34394 GIT binary patch literal 9499 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 literal 0 HcmV?d00001 diff --git a/jhipster/src/main/webapp/content/images/logo-jhipster.png b/jhipster/src/main/webapp/content/images/logo-jhipster.png new file mode 100644 index 0000000000000000000000000000000000000000..d8eb48da05c157571eed9fd7303f8d9566f2ea12 GIT binary patch literal 4459 zcmX|E1yB@V)238FK~j(qNkODUIgmU;(gO(*P${JZ=?3XM8YCs8kB$SRLmH0mJmRPW zjygDwxc}z=zWHYM-FJ7N_u1LmnVoqzLJOo!LC!=@KtMpDs-mckzrWy*J1H?wbcBiIKI{l~?l|FQ8} zGHf6(+!t^B7X_K9f{bfoefMF_h_P-2VhbNfP4`Pj4&zy(j>UKvG2D*N^Cq~ z3ULNT!6=*t3j-aGm&Rya2O$w2`K^=SsxjR0HtuxidS@xe$9fOe){q>6Ma&n5xud3f zXId+p(!xQBBTODckT6%=#XjzMrY9%*WNrvC(g~~1#bM@f$T7!)F>b%%r`|&&MTxDy z!O+COn=9hJxj*L-JH@Zfj;7-=_>W5}WdMaao@(9S|ZqIR7s7ut2 zRO%LPYr1)0d}d-)EOdCaF55pWI_Zazx`G-P2RAV>@!8s_UG^}KO+iXV7MWg(A7sSr z_efP`c@YGXpP!eVlTG&}D`(FLc@R8?9{`YxHb{qn-wCvDW+EGJ zElW?f_TlvtI&`K#aao|+bLQSgwp%O`F+S3m{XYGBjnPednx=>?{N(x zqvhlXI|2%;{U)c9lZfFoHzjk)O$733PeHPHS!wW{oHvFz`@#u8{5?Fo_Gd@U7g-nM z18myb1IANM1va-Q|NL^a%AKL?Tq%C`?ufGBZfY|i@I>U4azx{{#4AfEX=vVtHI8~U zkA!1nWv5N5IV2o*H(&aQCGcq2^;qECmXh-6Q_}#{*z5h+;Kh^O^HWYhH3JEYES%&b zn~`IQ4wS_3-GPLjbm^uQ9`8#*Np5r~?w!#3DUdUjU%W~f(;qWT-KNePOb4pohLdh~ zaW7E_M_L^Cqlm)<0BL8gQS$*Wq|$s|NoiX?30DYG`!#798_Mw8#H1GORusc9N6CUU zP@f%DBQw)FigQ|Xo}2g0b_nJyft<}!g~9G9ACjd}ynGVcO=b3}pvoBd`!%iDpD80M ziDoEmFvDhIWgTUL$1Y!W>lmfcl?8=}_Vg*ymq5WoA|iO!wpMt2h0J3Nv(esXqMh)u zCnGVu8xcw_nQt!piI`~vh8e!XKE>)N=F>wWbsVWk470IAZ7enF*+LsBCIt zrVUJ&R2^m7|er zR`k5JtaQ}dyu&>(#K4Ybfp0R@N8*r4+B~1Pq-6CqR`lxLqA`5k)mNbAJI2~;)mF@? zb;as@o`Sae%~#})Wk^Ylg1%R)qp~P%pU$vS?c`OKpg>7UOw=vhwB8VQ*6$m<^1DRb z=X{oCCc*0A&Ed+Q5?C^Ip|qC#h5FfB^R^31TDut*nRn<^#b3NQMSJw;A&v8T1n}jb zpnwuCrFPuF0%^i0ZlGiC8tr7JjA2#57toQr9M5ucNj|({?XY*0-q>$c>uN>)oBr7? z<{|eMZN@9QzT+KWYpTZtIK8L48w{}b63NmSo_I@cXZ?rY&Qwd0*J`eqCTF>SYfMC? z``;AgDi7}Hr6v06eQFrBrl8S!&G5c(%Fckt$;F`GyO{%Tt05G^7khxZSwZp(68n); z6?*8is~k`Wars8O!dUEElYgCWWyRHiN=58p$C^?>LW;KbG+^Hbs@u5B-cfmrKvwh@ z*&F**D^}nu_gTyNo~+B%c&|T%A!s=&63Q9j_&t!Az@0mJ??eve?u^f+k1pI)39k%B zQ%CRe^4!x-gFqU&K55%+Lp#3Rd#RH)6~slq37;p8LC=k)TeR_hLUPmn^NQ=AQ(+); ziU*JfPHgJ*XgPH=Q~<3uw)LMS=dQZlQxrV-7|x>%rQo9$+yg7)Xll*}TN9L;#g0YyG+5zfcN5Ou)ef_O&HZPzR0Is+goj`iUR;ca)<#R7at8nf>X#8 zfk3V+JN=>L*GO3#b~a{@$i{mU81eAfydg{|>$+R|Y!ee4+sw+@>m-wLS+xGMC{dd# z#8Jr37&Uc%4!Dasduy`mm6A;KfWq;|n0tp$;@cTzH+Iw!wl#;0%VjP5W5$<`{bMAp zjbuzd=sG-apRTJJ18USIeQ%N_RH}b%D6c-OQU$W(ebunRT z>W}VLA`hY-S#1E$^gR?3M*4X6JdOticP#mszBkRTu3`322pW?wJFZfpN8tPJ4%g!+ zD0-H5QPE|G*moD7gbUbW`_1l;5+lCXHQl-P40iwiAdkY+9Ly4vU8Y+))PHM6E5yTL z`EG|{P9--wb|YuoXgb?}n|LqGY2{#K_F6=O^mtmO7~z2YAbTj&)zYeC*`g`QeqM37bl%$mk2m^@@y&WEwtQXhdSL`c6)0J zS9;!6)92o+OptB0cG)f2QenpN3%SK()G}pmOAlw z;V;Jwcr|pc#yOsi56A88BsX<;n2T)0tR0GbJy)a7-P(#?h^R6XWKI%WT7KU6cp-*R z))-sFUI}hMaGi<1v`^3KwoTO_t8^(e3a7-hm!*xWFPbp+EwlW9yJpo7k#tVp&AMy; z#CbKRssTPPgTz{;cG&P;ks zCK=NTkv9~J{(jY(&vi7QzQQ9lx=r>(=q&3?vC>x^g}V9qA>|GH7n1e49$HhxbtU@g zurasC?2 zpSV+LOR8ry;d`rq(;nM7)zD9dFL{I_1L02;h}u;-T540Mdh%O!qAiX#0I033rG@sF zE2bjRr?i0+V&4KPU+*S)8gzLt2{=cb-f5fwSu!NL9kRsxyI5Wy{BH1S*SIUbnj7N5 z)z=`wLHg%o+dEN3XJZ3}XboI|; zw$wN=wz)#G?^5$Q!+%HHMa1(5bUTtD5l$oW;ld;pfXmx1N);-qi09(zj-6xLsoZy# zh|R~HP;R-_X$X7Y8n3}XK5k{?}!pLX)rY{_UUfu#VUb{(7$|a7K169Sg5ld|Up*q5gfl@ChTK{qZb-;uhx{ z%Le-;u|%5UOyw@?F@^HCuF24RY9Tl4+EJz0mxdoQbg^08G$ltWIH#SyQNI=xu5?;>Amv4PB-Q^XbyB^*O>oqurI-2z% z!jbbv%2#2{(TNFfSgsq^=P&*(*RFTQ_h$ra)tsTv`UZg2)!u%L7>I0ns=5mEd%93d z+8wSQITdztdd2Y6zgp|W%g~Pn%SlLH1E{=v;gI}il|Nejy>9U@njE5pAqF7{(B77$ zxCCgZNhcTgmMK(^Ebz7V3mGcw`>pP&!(XFjttWpDNu;5&E=Re+w3=^x{~)19f+~iOopzsOqPCO^+0B(Q-PVeg^emHYpY_2J|xyo{9yA9|~+- zJAJ6^(+%oCu?Z%sbAJ$nxYItG!)yi|5FAz-T-idyryDq%Y2fLrVX#vSEo4bEb=*@VxG&b#1g { + dd { + margin-bottom: 15px; + } +} + +@media screen and (min-width: 768px) { + .row.jh-entity-details > { + dt { + margin-bottom: 15px; + } + dd { + border-bottom: 1px solid #eee; + padding-left: 180px; + margin-left: 0; + } + } +} + +/* ========================================================================== +ui bootstrap tweaks +========================================================================== */ +.nav, .pagination, .carousel, .panel-title a { + cursor: pointer; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table .btn-default, +.uib-datepicker-popup > li > div.uib-datepicker > table .btn-default { + border: 0; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table:focus, +.uib-datepicker-popup > li > div.uib-datepicker > table:focus { + outline: none; +} + + +/* jhipster-needle-scss-add-main JHipster will add new css style */ diff --git a/jhipster/src/main/webapp/content/scss/vendor.scss b/jhipster/src/main/webapp/content/scss/vendor.scss new file mode 100644 index 0000000000..55990bbef5 --- /dev/null +++ b/jhipster/src/main/webapp/content/scss/vendor.scss @@ -0,0 +1,10 @@ +/* after changing this file run 'npm install' or 'npm run webpack:build' */ +$fa-font-path: '~font-awesome/fonts'; + +/*************************** +put Sass variables here: +eg $input-color: red; +****************************/ + +@import 'node_modules/bootstrap/scss/bootstrap'; +@import 'node_modules/font-awesome/scss/font-awesome'; diff --git a/jhipster/src/main/webapp/favicon.ico b/jhipster/src/main/webapp/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..44c7595f58f5a2c52f5e21451e5e6868d6caea7f GIT binary patch literal 5430 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 user has been activated. Please ", + "error": "Your user could not be activated. Please use the registration form to sign up." + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/audits.json b/jhipster/src/main/webapp/i18n/en/audits.json new file mode 100644 index 0000000000..ed5e16d4c5 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/audits.json @@ -0,0 +1,27 @@ +{ + "audits": { + "title": "Audits", + "filter": { + "title": "Filter per date", + "from": "from", + "to": "to", + "button": { + "weeks": "Weeks", + "today": "today", + "clear": "clear", + "close": "close" + } + }, + "table": { + "header": { + "principal": "User", + "date": "Date", + "status": "State", + "data": "Extra data" + }, + "data": { + "remoteAddress": "Remote Address:" + } + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/comment.json b/jhipster/src/main/webapp/i18n/en/comment.json new file mode 100644 index 0000000000..eed148855a --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/comment.json @@ -0,0 +1,23 @@ +{ + "baeldungApp": { + "comment" : { + "home": { + "title": "Comments", + "createLabel": "Create a new Comment", + "createOrEditLabel": "Create or edit a Comment" + }, + "created": "A new Comment is created with identifier {{ param }}", + "updated": "A Comment is updated with identifier {{ param }}", + "deleted": "A Comment is deleted with identifier {{ param }}", + "delete": { + "question": "Are you sure you want to delete Comment {{ id }}?" + }, + "detail": { + "title": "Comment" + }, + "text": "Text", + "creationDate": "Creation Date", + "post": "Post" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/configuration.json b/jhipster/src/main/webapp/i18n/en/configuration.json new file mode 100644 index 0000000000..81e208de5c --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/configuration.json @@ -0,0 +1,10 @@ +{ + "configuration": { + "title": "Configuration", + "filter": "Filter (by prefix)", + "table": { + "prefix": "Prefix", + "properties": "Properties" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/error.json b/jhipster/src/main/webapp/i18n/en/error.json new file mode 100644 index 0000000000..65246c3b03 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/error.json @@ -0,0 +1,6 @@ +{ + "error": { + "title": "Error page!", + "403": "You are not authorized to access the page." + } +} diff --git a/jhipster/src/main/webapp/i18n/en/gateway.json b/jhipster/src/main/webapp/i18n/en/gateway.json new file mode 100644 index 0000000000..8c8bbd7e98 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/gateway.json @@ -0,0 +1,15 @@ +{ + "gateway": { + "title": "Gateway", + "routes": { + "title": "Current routes", + "url": "URL", + "service": "service", + "servers": "Available servers", + "error": "Warning: no server available!" + }, + "refresh": { + "button": "Refresh" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/global.json b/jhipster/src/main/webapp/i18n/en/global.json new file mode 100644 index 0000000000..0c49362336 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/global.json @@ -0,0 +1,133 @@ +{ + "global": { + "title": "Baeldung", + "browsehappy": "You are using an outdated browser. Please upgrade your browser to improve your experience.", + "menu": { + "home": "Home", + "jhipster-needle-menu-add-element": "JHipster will add additional menu entries here (do not translate!)", + "entities": { + "main": "Entities", + "post": "Post", + "comment": "Comment", + "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" + }, + "account": { + "main": "Account", + "settings": "Settings", + "password": "Password", + "sessions": "Sessions", + "login": "Sign in", + "logout": "Sign out", + "register": "Register" + }, + "admin": { + "main": "Administration", + "userManagement": "User management", + "tracker": "User tracker", + "metrics": "Metrics", + "health": "Health", + "configuration": "Configuration", + "logs": "Logs", + "audits": "Audits", + "apidocs": "API", + "database": "Database", + "jhipster-needle-menu-add-admin-element": "JHipster will add additional menu entries here (do not translate!)" + }, + "language": "Language" + }, + "form": { + "username": "Username", + "username.placeholder": "Your username", + "newpassword": "New password", + "newpassword.placeholder": "New password", + "confirmpassword": "New password confirmation", + "confirmpassword.placeholder": "Confirm the new password", + "email": "E-mail", + "email.placeholder": "Your e-mail" + }, + "messages": { + "info": { + "authenticated": { + "prefix": "If you want to ", + "link": "sign in", + "suffix": ", you can try the default accounts:
- Administrator (login=\"admin\" and password=\"admin\")
- User (login=\"user\" and password=\"user\")." + }, + "register": { + "noaccount": "You don't have an account yet?", + "link": "Register a new account" + } + }, + "error": { + "dontmatch": "The password and its confirmation do not match!" + }, + "validate": { + "newpassword": { + "required": "Your password is required.", + "minlength": "Your password is required to be at least 4 characters.", + "maxlength": "Your password cannot be longer than 50 characters.", + "strength": "Password strength:" + }, + "confirmpassword": { + "required": "Your confirmation password is required.", + "minlength": "Your confirmation password is required to be at least 4 characters.", + "maxlength": "Your confirmation password cannot be longer than 50 characters." + }, + "email": { + "required": "Your e-mail is required.", + "invalid": "Your e-mail is invalid.", + "minlength": "Your e-mail is required to be at least 5 characters.", + "maxlength": "Your e-mail cannot be longer than 50 characters." + } + } + }, + "field": { + "id": "ID" + }, + "ribbon": { + "dev":"Development" + } + }, + "entity": { + "action": { + "addblob": "Add blob", + "addimage": "Add image", + "back": "Back", + "cancel": "Cancel", + "delete": "Delete", + "edit": "Edit", + "open": "Open", + "save": "Save", + "view": "View" + }, + "detail": { + "field": "Field", + "value": "Value" + }, + "delete": { + "title": "Confirm delete operation" + }, + "validation": { + "required": "This field is required.", + "minlength": "This field is required to be at least {{ min }} characters.", + "maxlength": "This field cannot be longer than {{ max }} characters.", + "min": "This field should be at least {{ min }}.", + "max": "This field cannot be more than {{ max }}.", + "minbytes": "This field should be at least {{ min }} bytes.", + "maxbytes": "This field cannot be more than {{ max }} bytes.", + "pattern": "This field should follow pattern {{ pattern }}.", + "number": "This field should be a number.", + "datetimelocal": "This field should be a date and time." + } + }, + "error": { + "internalServerError": "Internal server error", + "server.not.reachable": "Server not reachable", + "url.not.found": "Not found", + "NotNull": "Field {{ fieldName }} cannot be empty!", + "Size": "Field {{ fieldName }} does not meet min/max size requirements!", + "userexists": "Login name already used!", + "emailexists": "E-mail is already in use!", + "idexists": "A new {{ entityName }} cannot already have an ID" + }, + "footer": "This is your footer" +} diff --git a/jhipster/src/main/webapp/i18n/en/health.json b/jhipster/src/main/webapp/i18n/en/health.json new file mode 100644 index 0000000000..868ea3fda4 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/health.json @@ -0,0 +1,27 @@ +{ + "health": { + "title": "Health Checks", + "refresh.button": "Refresh", + "stacktrace": "Stacktrace", + "details": { + "details": "Details", + "properties": "Properties", + "name": "Name", + "value": "Value", + "error": "Error" + }, + "indicator": { + "diskSpace": "Disk space", + "mail": "Email", + "db": "Database" + }, + "table": { + "service": "Service name", + "status": "Status" + }, + "status": { + "UP": "UP", + "DOWN": "DOWN" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/home.json b/jhipster/src/main/webapp/i18n/en/home.json new file mode 100644 index 0000000000..402f18700a --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/home.json @@ -0,0 +1,19 @@ +{ + "home": { + "title": "Welcome, Java Hipster!", + "subtitle": "This is your homepage", + "logged": { + "message": "You are logged in as user \"{{username}}\"." + }, + "question": "If you have any question on JHipster:", + "link": { + "homepage": "JHipster homepage", + "stackoverflow": "JHipster on Stack Overflow", + "bugtracker": "JHipster bug tracker", + "chat": "JHipster public chat room", + "follow": "follow @java_hipster on Twitter" + }, + "like": "If you like JHipster, don't forget to give us a star on", + "github": "GitHub" + } +} diff --git a/jhipster/src/main/webapp/i18n/en/login.json b/jhipster/src/main/webapp/i18n/en/login.json new file mode 100644 index 0000000000..3a000852e6 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/login.json @@ -0,0 +1,19 @@ +{ + "login": { + "title": "Sign in", + "form": { + "password": "Password", + "password.placeholder": "Your password", + "rememberme": "Remember me", + "button": "Sign in" + }, + "messages": { + "error": { + "authentication": "Failed to sign in! Please check your credentials and try again." + } + }, + "password" : { + "forgot": "Did you forget your password?" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/logs.json b/jhipster/src/main/webapp/i18n/en/logs.json new file mode 100644 index 0000000000..a614b128da --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/logs.json @@ -0,0 +1,11 @@ +{ + "logs": { + "title": "Logs", + "nbloggers": "There are {{ total }} loggers.", + "filter": "Filter", + "table": { + "name": "Name", + "level": "Level" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/metrics.json b/jhipster/src/main/webapp/i18n/en/metrics.json new file mode 100644 index 0000000000..9d804947c5 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/metrics.json @@ -0,0 +1,101 @@ +{ + "metrics": { + "title": "Application Metrics", + "refresh.button": "Refresh", + "updating": "Updating...", + "jvm": { + "title": "JVM Metrics", + "memory": { + "title": "Memory", + "total": "Total Memory", + "heap": "Heap Memory", + "nonheap": "Non-Heap Memory" + }, + "threads": { + "title": "Threads", + "all": "All", + "runnable": "Runnable", + "timedwaiting": "Timed waiting", + "waiting": "Waiting", + "blocked": "Blocked", + "dump": { + "title": "Threads dump", + "id": "Id: ", + "blockedtime": "Blocked Time", + "blockedcount": "Blocked Count", + "waitedtime": "Waited Time", + "waitedcount": "Waited Count", + "lockname": "Lock name", + "stacktrace": "Stacktrace", + "show": "Show Stacktrace", + "hide": "Hide Stacktrace" + } + }, + "gc": { + "title": "Garbage collections", + "marksweepcount": "Mark Sweep count", + "marksweeptime": "Mark Sweep time", + "scavengecount": "Scavenge count", + "scavengetime": "Scavenge time" + }, + "http": { + "title": "HTTP requests (events per second)", + "active": "Active requests:", + "total": "Total requests:", + "table": { + "code": "Code", + "count": "Count", + "mean": "Mean", + "average": "Average" + }, + "code": { + "ok": "Ok", + "notfound": "Not found", + "servererror": "Server Error" + } + } + }, + "servicesstats": { + "title": "Services statistics (time in millisecond)", + "table": { + "name": "Service name", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + }, + "cache": { + "title": "Cache statistics", + "cachename": "Cache name", + "hits": "Cache Hits", + "misses": "Cache Misses", + "gets": "Cache Gets", + "puts": "Cache Puts", + "removals": "Cache Removals", + "evictions": "Cache Evictions", + "hitPercent": "Cache Hit %", + "missPercent": "Cache Miss %", + "averageGetTime": "Average get time (µs)", + "averagePutTime": "Average put time (µs)", + "averageRemoveTime": "Average remove time (µs)" + }, + "datasource": { + "usage": "Usage", + "title": "DataSource statistics (time in millisecond)", + "name": "Pool usage", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/password.json b/jhipster/src/main/webapp/i18n/en/password.json new file mode 100644 index 0000000000..46227a7702 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/password.json @@ -0,0 +1,12 @@ +{ + "password": { + "title": "Password for [{{username}}]", + "form": { + "button": "Save" + }, + "messages": { + "error": "An error has occurred! The password could not be changed.", + "success": "Password changed!" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/post.json b/jhipster/src/main/webapp/i18n/en/post.json new file mode 100644 index 0000000000..14c64f3f90 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/post.json @@ -0,0 +1,24 @@ +{ + "baeldungApp": { + "post" : { + "home": { + "title": "Posts", + "createLabel": "Create a new Post", + "createOrEditLabel": "Create or edit a Post" + }, + "created": "A new Post is created with identifier {{ param }}", + "updated": "A Post is updated with identifier {{ param }}", + "deleted": "A Post is deleted with identifier {{ param }}", + "delete": { + "question": "Are you sure you want to delete Post {{ id }}?" + }, + "detail": { + "title": "Post" + }, + "title": "Title", + "content": "Content", + "creationDate": "Creation Date", + "creator": "Creator" + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/register.json b/jhipster/src/main/webapp/i18n/en/register.json new file mode 100644 index 0000000000..df8f6e31b8 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/register.json @@ -0,0 +1,24 @@ +{ + "register": { + "title": "Registration", + "form": { + "button": "Register" + }, + "messages": { + "validate": { + "login": { + "required": "Your username is required.", + "minlength": "Your username is required to be at least 1 character.", + "maxlength": "Your username cannot be longer than 50 characters.", + "pattern": "Your username can only contain lower-case letters and digits." + } + }, + "success": "Registration saved! Please check your email for confirmation.", + "error": { + "fail": "Registration failed! Please try again later.", + "userexists": "Login name already registered! Please choose another one.", + "emailexists": "E-mail is already in use! Please choose another one." + } + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/reset.json b/jhipster/src/main/webapp/i18n/en/reset.json new file mode 100644 index 0000000000..fc61e0070f --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/reset.json @@ -0,0 +1,27 @@ +{ + "reset": { + "request": { + "title": "Reset your password", + "form": { + "button": "Reset password" + }, + "messages": { + "info": "Enter the e-mail address you used to register", + "success": "Check your e-mails for details on how to reset your password.", + "notfound": "E-Mail address isn't registered! Please check and try again" + } + }, + "finish" : { + "title": "Reset password", + "form": { + "button": "Validate new password" + }, + "messages": { + "info": "Choose a new password", + "success": "Your password has been reset. Please ", + "keymissing": "The reset key is missing.", + "error": "Your password couldn't be reset. Remember a password request is only valid for 24 hours." + } + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/sessions.json b/jhipster/src/main/webapp/i18n/en/sessions.json new file mode 100644 index 0000000000..d410035ee7 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/sessions.json @@ -0,0 +1,15 @@ +{ + "sessions": { + "title": "Active sessions for [{{username}}]", + "table": { + "ipaddress": "IP address", + "useragent": "User Agent", + "date": "Date", + "button": "Invalidate" + }, + "messages": { + "success": "Session invalidated!", + "error": "An error has occurred! The session could not be invalidated." + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/settings.json b/jhipster/src/main/webapp/i18n/en/settings.json new file mode 100644 index 0000000000..919ab51cc9 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/settings.json @@ -0,0 +1,32 @@ +{ + "settings": { + "title": "User settings for [{{username}}]", + "form": { + "firstname": "First Name", + "firstname.placeholder": "Your first name", + "lastname": "Last Name", + "lastname.placeholder": "Your last name", + "language": "Language", + "button": "Save" + }, + "messages": { + "error": { + "fail": "An error has occurred! Settings could not be saved.", + "emailexists": "E-mail is already in use! Please choose another one." + }, + "success": "Settings saved!", + "validate": { + "firstname": { + "required": "Your first name is required.", + "minlength": "Your first name is required to be at least 1 character", + "maxlength": "Your first name cannot be longer than 50 characters" + }, + "lastname": { + "required": "Your last name is required.", + "minlength": "Your last name is required to be at least 1 character", + "maxlength": "Your last name cannot be longer than 50 characters" + } + } + } + } +} diff --git a/jhipster/src/main/webapp/i18n/en/user-management.json b/jhipster/src/main/webapp/i18n/en/user-management.json new file mode 100644 index 0000000000..30c125b6d0 --- /dev/null +++ b/jhipster/src/main/webapp/i18n/en/user-management.json @@ -0,0 +1,30 @@ +{ + "userManagement": { + "home": { + "title": "Users", + "createLabel": "Create a new user", + "createOrEditLabel": "Create or edit a user" + }, + "created": "A new user is created with identifier {{ param }}", + "updated": "An user is updated with identifier {{ param }}", + "deleted": "An user is deleted with identifier {{ param }}", + "delete": { + "question": "Are you sure you want to delete user {{ login }}?" + }, + "detail": { + "title": "User" + }, + "login": "Login", + "firstName": "First name", + "lastName": "Last name", + "email": "Email", + "activated": "Activated", + "deactivated": "Deactivated", + "profiles": "Profiles", + "langKey": "Language", + "createdBy": "Created by", + "createdDate": "Created date", + "lastModifiedBy": "Modified by", + "lastModifiedDate": "Modified date" + } +} diff --git a/jhipster/src/main/webapp/index.html b/jhipster/src/main/webapp/index.html new file mode 100644 index 0000000000..6227d62823 --- /dev/null +++ b/jhipster/src/main/webapp/index.html @@ -0,0 +1,27 @@ + + + + + + + baeldung + + + + + + + + + + diff --git a/jhipster/src/main/webapp/robots.txt b/jhipster/src/main/webapp/robots.txt new file mode 100644 index 0000000000..7de2585cf6 --- /dev/null +++ b/jhipster/src/main/webapp/robots.txt @@ -0,0 +1,11 @@ +# robotstxt.org/ + +User-agent: * +Disallow: /api/account +Disallow: /api/account/change_password +Disallow: /api/account/sessions +Disallow: /api/audits/ +Disallow: /api/logs/ +Disallow: /api/users/ +Disallow: /management/ +Disallow: /v2/api-docs/ diff --git a/jhipster/src/main/webapp/swagger-ui/images/throbber.gif b/jhipster/src/main/webapp/swagger-ui/images/throbber.gif new file mode 100644 index 0000000000000000000000000000000000000000..06393889242fb3ea9e0205fa84369ec7bb66d15a GIT binary patch literal 9257 zcmd^^X;@R|x`tQg5wbE8AV3mAn1TjmQ&en2CK8~ENEH<+P_)pZ24y2E+7O0>K^a6u zQ3;5MiU^7p6*M3qDk!2=YEcHMQ>nzEYP;R`e2C@r+U+?#XaC*&gKPcB#k$`o&;7mu zYNhYYXe|Uo84#4ZIko#rcU5K8*yFL{qT47O&^5fZH$ zVZ@%(l~vVHjnm;H@KL8@r%yUHoo;rbHI_4lIH(_nsTT>S2`DFOD~uCb9_dF4`#QgI zy7ldMcLs+A_s%|e1pRPrbX-tpeNP!9(IpMFTce`t_5U%lP99z%&i6`1d~ zWeM!Rxc50<+d$e^9LT`?B+aMK~apR zHm?q;p<7{wN2g|I^aGlSws;VP84j(z%aQwvAWv83Z$}p(% zZ^?2;gxg(ey_`V5J7{;!o;o;KslW@z5EP~JGs|U)J7dF&(ff#A=6vU?cGQ$-4+;Jf z-ggJEa!yStn`_EWvl)#yhm6XVs}UUbsi;+agri;mCfjH^Uy;lH+Zw^h)4N?oZgZz4 zJk(fTZ|Bi^;+s_M=~+d#vyoxEPzTlOS=mX@sbl*uRj>=MaMr}cFIY8i?UM61>86uB zV$DlOUCiUJwbzJMP@D$urzK|lL2-PC!p1l47V-ZG<5Ev0Z5h~Kx?`KOp7gkAjV93A z-Gc7MrlxTf?wF;CbNc@tCHJH{TB3c;#{SVu%97}tyAM2n&|9W_?qv}$*Jt*%7Yxb# zV0;d;7|lDEltJYS+U)#aiJO};?_Jyy_4%syQ(uy?-J-Yx-9O5nKRk@@XSS~X<(2u~ zV-LamWm~!iqtH9wkpf8mAXZhOD&L#aA_%)4h2M;1M5jt zIR>Us+%W-GXa_f^opKg=DSrAs)AXeRa;Hp0aC1OgbxQ%Qr_QvTleM1jkR!2mkcX$3 ztsR8~G9iqh(-FJ@F_rQBIYDXV_6s7G9SxaVF^laZqcx$!D97m|7t16j6@Jt6UdDRy49Qyvs|c>RuA|@b%}`*wU}2^7q;&Vtc6@lb zcXl)T!6nYDzmMJ~%n$KNXyNlCG)GkJ4!82;v6@d3>s5r~E+3!O?049JDr14Y^PeMI02R`0lJ^=oJ zYd|*u9|SU(j7hY?+<=(?fP*mtV*zFhOrz6%{VA?ozdm&(Jf^V zMfPZ?>l`mS3{Uq8IM;e!+1YjJy2!mzK$O|wPeU{*QSbs9m+@`f5KxO3PBnQ=%RsZg%go*fJ`*w9TL{-WgZVIA$!YV}3BRcfeXaR$x#b zW)Tpd#8E4)^MyYdkH;4_;ChJuw%n+Be7Ko4;w-nHvyo$d_0e-YiF78Df&)_)(}fcr_r0mPH(4RRYWIu+d@t0&Ss@O^s! zOKyX&13)%N@83r^;QsgN{rl(!0|RF1FA)b1{CRXAy&1ySz@>olPiR4r$aMdq&_=nK zq|cFs8phWJ1@%dZ-gXd{zDbTILD>)qEvH-NU*Rf1b2J1Ri79`rBFl@ z8E^0I)OqEi{pH(a24b9YPG;Kz@t-qZW;3Mpe`MRlmYx{7bH-XZ&`RQ7Rb^%}gc&X| zd}Q-FZf|RWxHU?PR!(C?80zu(^l>*h{#ulSiid(O!J(8P-41bNM3tnX@U6NS5yo0? zdcF)~xFE&+&|gZ$23dV5t~?$$&ymZ;F8j7GGMncGSsDo%>J`26=&l=X#rSKv_64;0 zr;k6no@=gV`P)K!=kaHl>q?!`X>(A;84tg^Md<`zA%qbRLby1Z=fn*ZRdNqs%Tq|3 zOt}lZu0q9oKJhgz&+^7PCt$=UFW=R*w?a1)ePoL*`R$Gxj?TU@12tTHsT$giHQU+sqf;fS0FpT!< z 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 + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+
+ + diff --git a/jhipster/src/test/gatling/conf/gatling.conf b/jhipster/src/test/gatling/conf/gatling.conf new file mode 100644 index 0000000000..e509853f22 --- /dev/null +++ b/jhipster/src/test/gatling/conf/gatling.conf @@ -0,0 +1,131 @@ +######################### +# Gatling Configuration # +######################### + +# This file contains all the settings configurable for Gatling with their default values + +gatling { + core { + #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp) + #runDescription = "" # The description for this simulation run, displayed in each report + #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation + #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated) + #mute = false # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin) + #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable + #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable + #rawFileBodiesInMemoryMaxSize = 1000 # Below this limit, raw file bodies will be cached in memory + + extract { + regex { + #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching + } + xpath { + #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching + } + jsonPath { + #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching + #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations + } + css { + #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching + } + } + directory { + #data = user-files/data # Folder where user's data (e.g. files used by Feeders) is located + #bodies = user-files/bodies # Folder where bodies are located + #simulations = user-files/simulations # Folder where the bundle's simulations are located + #reportsOnly = "" # If set, name of report folder to look for in order to generate its report + #binaries = "" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target. + #results = results # Name of the folder where all reports folder are located + } + } + charting { + #noReports = false # When set to true, don't generate HTML reports + #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports + #useGroupDurationMetric = false # Switch group timings from cumulated response time to group duration. + indicators { + #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary + #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary + #percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and Graphite + #percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and Graphite + #percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and Graphite + #percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and Graphite + } + } + http { + #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable + #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable + #perUserCacheMaxCapacity = 200 # Per virtual user cache size, set to 0 to disable + #warmUpUrl = "http://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled) + #enableGA = true # Very light Google Analytics, please support + ssl { + keyStore { + #type = "" # Type of SSLContext's KeyManagers store + #file = "" # Location of SSLContext's KeyManagers store + #password = "" # Password for SSLContext's KeyManagers store + #algorithm = "" # Algorithm used SSLContext's KeyManagers store + } + trustStore { + #type = "" # Type of SSLContext's TrustManagers store + #file = "" # Location of SSLContext's TrustManagers store + #password = "" # Password for SSLContext's TrustManagers store + #algorithm = "" # Algorithm used by SSLContext's TrustManagers store + } + } + ahc { + #keepAlive = true # Allow pooling HTTP connections (keep-alive header automatically added) + #connectTimeout = 10000 # Timeout when establishing a connection + #handshakeTimeout = 10000 # Timeout when performing TLS hashshake + #pooledConnectionIdleTimeout = 60000 # Timeout when a connection stays unused in the pool + #readTimeout = 60000 # Timeout when a used connection stays idle + #maxRetry = 2 # Number of times that a request should be tried again + #requestTimeout = 60000 # Timeout of the requests + #acceptAnyCertificate = true # When set to true, doesn't validate SSL certificates + #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") + #httpClientCodecMaxHeaderSize = 8192 # Maximum size, in bytes, of each request's headers + #httpClientCodecMaxChunkSize = 8192 # Maximum length of the content or each chunk + #webSocketMaxFrameSize = 10240000 # Maximum frame payload size + #sslEnabledProtocols = [TLSv1.2, TLSv1.1, TLSv1] # Array of enabled protocols for HTTPS, if empty use the JDK defaults + #sslEnabledCipherSuites = [] # Array of enabled cipher suites for HTTPS, if empty use the AHC defaults + #sslSessionCacheSize = 0 # SSLSession cache size, set to 0 to use JDK's default + #sslSessionTimeout = 0 # SSLSession timeout in seconds, set to 0 to use JDK's default (24h) + #useOpenSsl = false # if OpenSSL should be used instead of JSSE (requires tcnative jar) + #useNativeTransport = false # if native transport should be used instead of Java NIO (requires netty-transport-native-epoll, currently Linux only) + #tcpNoDelay = true + #soReuseAddress = false + #soLinger = -1 + #soSndBuf = -1 + #soRcvBuf = -1 + #allocator = "pooled" # switch to unpooled for unpooled ByteBufAllocator + #maxThreadLocalCharBufferSize = 200000 # Netty's default is 16k + } + dns { + #queryTimeout = 5000 # Timeout of each DNS query in millis + #maxQueriesPerResolve = 6 # Maximum allowed number of DNS queries for a given name resolution + } + } + jms { + #acknowledgedMessagesBufferSize = 5000 # size of the buffer used to tracked acknowledged messages and protect against duplicate receives + } + data { + #writers = [console, file] # The list of DataWriters to which Gatling write simulation data (currently supported : console, file, graphite, jdbc) + console { + #light = false # When set to true, displays a light version without detailed request stats + } + file { + #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes + } + leak { + #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening + } + graphite { + #light = false # only send the all* stats + #host = "localhost" # The host where the Carbon server is located + #port = 2003 # The port to which the Carbon server listens to (2003 is default for plaintext, 2004 is default for pickle) + #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp") + #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite + #bufferSize = 8192 # GraphiteDataWriter's internal data buffer size, in bytes + #writeInterval = 1 # GraphiteDataWriter's write interval, in seconds + } + } +} diff --git a/jhipster/src/test/gatling/conf/logback.xml b/jhipster/src/test/gatling/conf/logback.xml new file mode 100644 index 0000000000..7b037e6813 --- /dev/null +++ b/jhipster/src/test/gatling/conf/logback.xml @@ -0,0 +1,22 @@ + + + + + + %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx + false + + + + + + + + + + + + + + + diff --git a/jhipster/src/test/gatling/simulations/CommentGatlingTest.scala b/jhipster/src/test/gatling/simulations/CommentGatlingTest.scala new file mode 100644 index 0000000000..93d066f9bb --- /dev/null +++ b/jhipster/src/test/gatling/simulations/CommentGatlingTest.scala @@ -0,0 +1,92 @@ +import _root_.io.gatling.core.scenario.Simulation +import ch.qos.logback.classic.{Level, LoggerContext} +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ + +/** + * Performance test for the Comment entity. + */ +class CommentGatlingTest extends Simulation { + + val context: LoggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] + // Log all HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")) + // Log failed HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")) + + val baseURL = Option(System.getProperty("baseURL")) getOrElse """http://127.0.0.1:8080""" + + val httpConf = http + .baseURL(baseURL) + .inferHtmlResources() + .acceptHeader("*/*") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") + .connectionHeader("keep-alive") + .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") + + val headers_http = Map( + "Accept" -> """application/json""" + ) + + val headers_http_authentication = Map( + "Content-Type" -> """application/json""", + "Accept" -> """application/json""" + ) + + val headers_http_authenticated = Map( + "Accept" -> """application/json""", + "Authorization" -> "${access_token}" + ) + + val scn = scenario("Test the Comment entity") + .exec(http("First unauthenticated request") + .get("/api/account") + .headers(headers_http) + .check(status.is(401))).exitHereIfFailed + .pause(10) + .exec(http("Authentication") + .post("/api/authenticate") + .headers(headers_http_authentication) + .body(StringBody("""{"username":"admin", "password":"admin"}""")).asJSON + .check(header.get("Authorization").saveAs("access_token"))).exitHereIfFailed + .pause(1) + .exec(http("Authenticated request") + .get("/api/account") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10) + .repeat(2) { + exec(http("Get all comments") + .get("/api/comments") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10 seconds, 20 seconds) + .exec(http("Create new comment") + .post("/api/comments") + .headers(headers_http_authenticated) + .body(StringBody("""{"id":null, "text":"SAMPLE_TEXT", "creationDate":"2020-01-01T00:00:00.000Z"}""")).asJSON + .check(status.is(201)) + .check(headerRegex("Location", "(.*)").saveAs("new_comment_url"))).exitHereIfFailed + .pause(10) + .repeat(5) { + exec(http("Get created comment") + .get("${new_comment_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + .exec(http("Delete created comment") + .delete("${new_comment_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + + val users = scenario("Users").exec(scn) + + setUp( + users.inject(rampUsers(100) over (1 minutes)) + ).protocols(httpConf) +} diff --git a/jhipster/src/test/gatling/simulations/PostGatlingTest.scala b/jhipster/src/test/gatling/simulations/PostGatlingTest.scala new file mode 100644 index 0000000000..d76198c9ae --- /dev/null +++ b/jhipster/src/test/gatling/simulations/PostGatlingTest.scala @@ -0,0 +1,92 @@ +import _root_.io.gatling.core.scenario.Simulation +import ch.qos.logback.classic.{Level, LoggerContext} +import io.gatling.core.Predef._ +import io.gatling.http.Predef._ +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ + +/** + * Performance test for the Post entity. + */ +class PostGatlingTest extends Simulation { + + val context: LoggerContext = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] + // Log all HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("TRACE")) + // Log failed HTTP requests + //context.getLogger("io.gatling.http").setLevel(Level.valueOf("DEBUG")) + + val baseURL = Option(System.getProperty("baseURL")) getOrElse """http://127.0.0.1:8080""" + + val httpConf = http + .baseURL(baseURL) + .inferHtmlResources() + .acceptHeader("*/*") + .acceptEncodingHeader("gzip, deflate") + .acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3") + .connectionHeader("keep-alive") + .userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0") + + val headers_http = Map( + "Accept" -> """application/json""" + ) + + val headers_http_authentication = Map( + "Content-Type" -> """application/json""", + "Accept" -> """application/json""" + ) + + val headers_http_authenticated = Map( + "Accept" -> """application/json""", + "Authorization" -> "${access_token}" + ) + + val scn = scenario("Test the Post entity") + .exec(http("First unauthenticated request") + .get("/api/account") + .headers(headers_http) + .check(status.is(401))).exitHereIfFailed + .pause(10) + .exec(http("Authentication") + .post("/api/authenticate") + .headers(headers_http_authentication) + .body(StringBody("""{"username":"admin", "password":"admin"}""")).asJSON + .check(header.get("Authorization").saveAs("access_token"))).exitHereIfFailed + .pause(1) + .exec(http("Authenticated request") + .get("/api/account") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10) + .repeat(2) { + exec(http("Get all posts") + .get("/api/posts") + .headers(headers_http_authenticated) + .check(status.is(200))) + .pause(10 seconds, 20 seconds) + .exec(http("Create new post") + .post("/api/posts") + .headers(headers_http_authenticated) + .body(StringBody("""{"id":null, "title":"SAMPLE_TEXT", "content":"SAMPLE_TEXT", "creationDate":"2020-01-01T00:00:00.000Z"}""")).asJSON + .check(status.is(201)) + .check(headerRegex("Location", "(.*)").saveAs("new_post_url"))).exitHereIfFailed + .pause(10) + .repeat(5) { + exec(http("Get created post") + .get("${new_post_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + .exec(http("Delete created post") + .delete("${new_post_url}") + .headers(headers_http_authenticated)) + .pause(10) + } + + val users = scenario("Users").exec(scn) + + setUp( + users.inject(rampUsers(100) over (1 minutes)) + ).protocols(httpConf) +} diff --git a/jhipster/src/test/java/com/baeldung/security/SecurityUtilsUnitTest.java b/jhipster/src/test/java/com/baeldung/security/SecurityUtilsUnitTest.java new file mode 100644 index 0000000000..b78a18790b --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/security/SecurityUtilsUnitTest.java @@ -0,0 +1,50 @@ +package com.baeldung.security; + +import org.junit.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; + +/** +* Test class for the SecurityUtils utility class. +* +* @see SecurityUtils +*/ +public class SecurityUtilsUnitTest { + + @Test + public void testgetCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + String login = SecurityUtils.getCurrentUserLogin(); + assertThat(login).isEqualTo("admin"); + } + + @Test + public void testIsAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin")); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isTrue(); + } + + @Test + public void testAnonymousIsNotAuthenticated() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities)); + SecurityContextHolder.setContext(securityContext); + boolean isAuthenticated = SecurityUtils.isAuthenticated(); + assertThat(isAuthenticated).isFalse(); + } +} diff --git a/jhipster/src/test/java/com/baeldung/security/jwt/TokenProviderTest.java b/jhipster/src/test/java/com/baeldung/security/jwt/TokenProviderTest.java new file mode 100644 index 0000000000..3fec4bfb88 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/security/jwt/TokenProviderTest.java @@ -0,0 +1,107 @@ +package com.baeldung.security.jwt; + +import com.baeldung.security.AuthoritiesConstants; +import io.github.jhipster.config.JHipsterProperties; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TokenProviderTest { + + private final String secretKey = "e5c9ee274ae87bc031adda32e27fa98b9290da83"; + private final long ONE_MINUTE = 60000; + private JHipsterProperties jHipsterProperties; + private TokenProvider tokenProvider; + + @Before + public void setup() { + jHipsterProperties = Mockito.mock(JHipsterProperties.class); + tokenProvider = new TokenProvider(jHipsterProperties); + ReflectionTestUtils.setField(tokenProvider, "secretKey", secretKey); + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE); + } + + @Test + public void testReturnFalseWhenJWThasInvalidSignature() { + boolean isTokenValid = tokenProvider.validateToken(createTokenWithDifferentSignature()); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisMalformed() { + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + String invalidToken = token.substring(1); + boolean isTokenValid = tokenProvider.validateToken(invalidToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisExpired() { + ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE); + + Authentication authentication = createAuthentication(); + String token = tokenProvider.createToken(authentication, false); + + boolean isTokenValid = tokenProvider.validateToken(token); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisUnsupported() { + Date expirationDate = new Date(new Date().getTime() + ONE_MINUTE); + + Authentication authentication = createAuthentication(); + + String unsupportedToken = createUnsupportedToken(); + + boolean isTokenValid = tokenProvider.validateToken(unsupportedToken); + + assertThat(isTokenValid).isEqualTo(false); + } + + @Test + public void testReturnFalseWhenJWTisInvalid() { + + boolean isTokenValid = tokenProvider.validateToken(""); + + assertThat(isTokenValid).isEqualTo(false); + } + + private Authentication createAuthentication() { + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS)); + return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities); + } + + private String createUnsupportedToken() { + return Jwts.builder() + .setPayload("payload") + .signWith(SignatureAlgorithm.HS512, secretKey) + .compact(); + } + + private String createTokenWithDifferentSignature() { + return Jwts.builder() + .setSubject("anonymous") + .signWith(SignatureAlgorithm.HS512, "e5c9ee274ae87bc031adda32e27fa98b9290da90") + .setExpiration(new Date(new Date().getTime() + ONE_MINUTE)) + .compact(); + } +} diff --git a/jhipster/src/test/java/com/baeldung/service/UserServiceIntTest.java b/jhipster/src/test/java/com/baeldung/service/UserServiceIntTest.java new file mode 100644 index 0000000000..968f0a7f08 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/service/UserServiceIntTest.java @@ -0,0 +1,129 @@ +package com.baeldung.service; + +import com.baeldung.BaeldungApp; +import com.baeldung.domain.User; +import com.baeldung.config.Constants; +import com.baeldung.repository.UserRepository; +import com.baeldung.service.dto.UserDTO; +import java.time.ZonedDateTime; +import com.baeldung.service.util.RandomUtil; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.test.context.junit4.SpringRunner; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import java.util.Optional; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +/** + * Test class for the UserResource REST controller. + * + * @see UserService + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +@Transactional +public class UserServiceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserService userService; + + @Test + public void assertThatUserMustExistToResetPassword() { + Optional maybeUser = userService.requestPasswordReset("john.doe@localhost"); + assertThat(maybeUser.isPresent()).isFalse(); + + maybeUser = userService.requestPasswordReset("admin@localhost"); + assertThat(maybeUser.isPresent()).isTrue(); + + assertThat(maybeUser.get().getEmail()).isEqualTo("admin@localhost"); + assertThat(maybeUser.get().getResetDate()).isNotNull(); + assertThat(maybeUser.get().getResetKey()).isNotNull(); + } + + @Test + public void assertThatOnlyActivatedUserCanRequestPasswordReset() { + User user = userService.createUser("johndoe", "johndoe", "John", "Doe", "john.doe@localhost", "http://placehold.it/50x50", "en-US"); + Optional maybeUser = userService.requestPasswordReset("john.doe@localhost"); + assertThat(maybeUser.isPresent()).isFalse(); + userRepository.delete(user); + } + + @Test + public void assertThatResetKeyMustNotBeOlderThan24Hours() { + User user = userService.createUser("johndoe", "johndoe", "John", "Doe", "john.doe@localhost", "http://placehold.it/50x50", "en-US"); + + ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + + userRepository.save(user); + + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + + assertThat(maybeUser.isPresent()).isFalse(); + + userRepository.delete(user); + } + + @Test + public void assertThatResetKeyMustBeValid() { + User user = userService.createUser("johndoe", "johndoe", "John", "Doe", "john.doe@localhost", "http://placehold.it/50x50", "en-US"); + + ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey("1234"); + userRepository.save(user); + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser.isPresent()).isFalse(); + userRepository.delete(user); + } + + @Test + public void assertThatUserCanResetPassword() { + User user = userService.createUser("johndoe", "johndoe", "John", "Doe", "john.doe@localhost", "http://placehold.it/50x50", "en-US"); + String oldPassword = user.getPassword(); + ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(2); + String resetKey = RandomUtil.generateResetKey(); + user.setActivated(true); + user.setResetDate(daysAgo); + user.setResetKey(resetKey); + userRepository.save(user); + Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey()); + assertThat(maybeUser.isPresent()).isTrue(); + assertThat(maybeUser.get().getResetDate()).isNull(); + assertThat(maybeUser.get().getResetKey()).isNull(); + assertThat(maybeUser.get().getPassword()).isNotEqualTo(oldPassword); + + userRepository.delete(user); + } + + @Test + public void testFindNotActivatedUsersByCreationDateBefore() { + userService.removeNotActivatedUsers(); + ZonedDateTime now = ZonedDateTime.now(); + List users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minusDays(3)); + assertThat(users).isEmpty(); + } + + @Test + public void assertThatAnonymousUserIsNotGet() { + final PageRequest pageable = new PageRequest(0, (int) userRepository.count()); + final Page allManagedUsers = userService.getAllManagedUsers(pageable); + assertThat(allManagedUsers.getContent().stream() + .noneMatch(user -> Constants.ANONYMOUS_USER.equals(user.getLogin()))) + .isTrue(); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/AccountResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/AccountResourceIntTest.java new file mode 100644 index 0000000000..e42ce1c6d4 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/AccountResourceIntTest.java @@ -0,0 +1,395 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; +import com.baeldung.domain.Authority; +import com.baeldung.domain.User; +import com.baeldung.repository.AuthorityRepository; +import com.baeldung.repository.UserRepository; +import com.baeldung.security.AuthoritiesConstants; +import com.baeldung.service.MailService; +import com.baeldung.service.UserService; +import com.baeldung.service.dto.UserDTO; +import com.baeldung.web.rest.vm.ManagedUserVM; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AccountResource REST controller. + * + * @see AccountResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class AccountResourceIntTest { + + @Autowired + private UserRepository userRepository; + + @Autowired + private AuthorityRepository authorityRepository; + + @Autowired + private UserService userService; + + @Mock + private UserService mockUserService; + + @Mock + private MailService mockMailService; + + private MockMvc restUserMockMvc; + + private MockMvc restMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(mockMailService).sendActivationEmail(anyObject()); + + AccountResource accountResource = + new AccountResource(userRepository, userService, mockMailService); + + AccountResource accountUserMockResource = + new AccountResource(userRepository, mockUserService, mockMailService); + + this.restMvc = MockMvcBuilders.standaloneSetup(accountResource).build(); + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build(); + } + + @Test + public void testNonAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("")); + } + + @Test + public void testAuthenticatedUser() throws Exception { + restUserMockMvc.perform(get("/api/authenticate") + .with(request -> { + request.setRemoteUser("test"); + return request; + }) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("test")); + } + + @Test + public void testGetExistingAccount() throws Exception { + Set authorities = new HashSet<>(); + Authority authority = new Authority(); + authority.setName(AuthoritiesConstants.ADMIN); + authorities.add(authority); + + User user = new User(); + user.setLogin("test"); + user.setFirstName("john"); + user.setLastName("doe"); + user.setEmail("john.doe@jhipster.com"); + user.setImageUrl("http://placehold.it/50x50"); + user.setAuthorities(authorities); + when(mockUserService.getUserWithAuthorities()).thenReturn(user); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value("test")) + .andExpect(jsonPath("$.firstName").value("john")) + .andExpect(jsonPath("$.lastName").value("doe")) + .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50")) + .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN)); + } + + @Test + public void testGetUnknownAccount() throws Exception { + when(mockUserService.getUserWithAuthorities()).thenReturn(null); + + restUserMockMvc.perform(get("/api/account") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isInternalServerError()); + } + + @Test + @Transactional + public void testRegisterValid() throws Exception { + ManagedUserVM validUser = new ManagedUserVM( + null, // id + "joe", // login + "password", // password + "Joe", // firstName + "Shmoe", // lastName + "joe@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + Optional user = userRepository.findOneByLogin("joe"); + assertThat(user.isPresent()).isTrue(); + } + + @Test + @Transactional + public void testRegisterInvalidLogin() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM( + null, // id + "funky-log!n", // login <-- invalid + "password", // password + "Funky", // firstName + "One", // lastName + "funky@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByEmail("funky@example.com"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidEmail() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM( + null, // id + "bob", // login + "password", // password + "Bob", // firstName + "Green", // lastName + "invalid", // e-mail <-- invalid + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterInvalidPassword() throws Exception { + ManagedUserVM invalidUser = new ManagedUserVM( + null, // id + "bob", // login + "123", // password with only 3 digits + "Bob", // firstName + "Green", // lastName + "bob@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + restUserMockMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByLogin("bob"); + assertThat(user.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterDuplicateLogin() throws Exception { + // Good + ManagedUserVM validUser = new ManagedUserVM( + null, // id + "alice", // login + "password", // password + "Alice", // firstName + "Something", // lastName + "alice@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + // Duplicate login, different e-mail + ManagedUserVM duplicatedUser = new ManagedUserVM(validUser.getId(), validUser.getLogin(), validUser.getPassword(), validUser.getLogin(), validUser.getLastName(), + "alicejr@example.com", true, validUser.getImageUrl(), validUser.getLangKey(), validUser.getCreatedBy(), validUser.getCreatedDate(), validUser.getLastModifiedBy(), validUser.getLastModifiedDate(), validUser.getAuthorities()); + + // Good user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + // Duplicate login + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(duplicatedUser))) + .andExpect(status().is4xxClientError()); + + Optional userDup = userRepository.findOneByEmail("alicejr@example.com"); + assertThat(userDup.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterDuplicateEmail() throws Exception { + // Good + ManagedUserVM validUser = new ManagedUserVM( + null, // id + "john", // login + "password", // password + "John", // firstName + "Doe", // lastName + "john@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER))); + + // Duplicate e-mail, different login + ManagedUserVM duplicatedUser = new ManagedUserVM(validUser.getId(), "johnjr", validUser.getPassword(), validUser.getLogin(), validUser.getLastName(), + validUser.getEmail(), true, validUser.getImageUrl(), validUser.getLangKey(), validUser.getCreatedBy(), validUser.getCreatedDate(), validUser.getLastModifiedBy(), validUser.getLastModifiedDate(), validUser.getAuthorities()); + + // Good user + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + // Duplicate e-mail + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(duplicatedUser))) + .andExpect(status().is4xxClientError()); + + Optional userDup = userRepository.findOneByLogin("johnjr"); + assertThat(userDup.isPresent()).isFalse(); + } + + @Test + @Transactional + public void testRegisterAdminIsIgnored() throws Exception { + ManagedUserVM validUser = new ManagedUserVM( + null, // id + "badguy", // login + "password", // password + "Bad", // firstName + "Guy", // lastName + "badguy@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.ADMIN))); + + restMvc.perform( + post("/api/register") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(validUser))) + .andExpect(status().isCreated()); + + Optional userDup = userRepository.findOneByLogin("badguy"); + assertThat(userDup.isPresent()).isTrue(); + assertThat(userDup.get().getAuthorities()).hasSize(1) + .containsExactly(authorityRepository.findOne(AuthoritiesConstants.USER)); + } + + @Test + @Transactional + public void testSaveInvalidLogin() throws Exception { + UserDTO invalidUser = new UserDTO( + null, // id + "funky-log!n", // login <-- invalid + "Funky", // firstName + "One", // lastName + "funky@example.com", // e-mail + true, // activated + "http://placehold.it/50x50", //imageUrl + "en", // langKey + null, // createdBy + null, // createdDate + null, // lastModifiedBy + null, // lastModifiedDate + new HashSet<>(Arrays.asList(AuthoritiesConstants.USER)) + ); + + restUserMockMvc.perform( + post("/api/account") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(invalidUser))) + .andExpect(status().isBadRequest()); + + Optional user = userRepository.findOneByEmail("funky@example.com"); + assertThat(user.isPresent()).isFalse(); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/AuditResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/AuditResourceIntTest.java new file mode 100644 index 0000000000..127cb36f07 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/AuditResourceIntTest.java @@ -0,0 +1,147 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; +import com.baeldung.config.audit.AuditEventConverter; +import com.baeldung.domain.PersistentAuditEvent; +import com.baeldung.repository.PersistenceAuditEventRepository; +import com.baeldung.service.AuditEventService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the AuditResource REST controller. + * + * @see AuditResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +@Transactional +public class AuditResourceIntTest { + + private static final String SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL"; + private static final String SAMPLE_TYPE = "SAMPLE_TYPE"; + private static final LocalDateTime SAMPLE_TIMESTAMP = LocalDateTime.parse("2015-08-04T10:11:30"); + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + @Autowired + private PersistenceAuditEventRepository auditEventRepository; + + @Autowired + private AuditEventConverter auditEventConverter; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private FormattingConversionService formattingConversionService; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + private PersistentAuditEvent auditEvent; + + private MockMvc restAuditMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + AuditEventService auditEventService = + new AuditEventService(auditEventRepository, auditEventConverter); + AuditResource auditResource = new AuditResource(auditEventService); + this.restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setConversionService(formattingConversionService) + .setMessageConverters(jacksonMessageConverter).build(); + } + + @Before + public void initTest() { + auditEventRepository.deleteAll(); + auditEvent = new PersistentAuditEvent(); + auditEvent.setAuditEventType(SAMPLE_TYPE); + auditEvent.setPrincipal(SAMPLE_PRINCIPAL); + auditEvent.setAuditEventDate(SAMPLE_TIMESTAMP); + } + + @Test + public void getAllAudits() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get all the audits + restAuditMockMvc.perform(get("/management/audits")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getAudit() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); + } + + @Test + public void getAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will contain the audit + String fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); + String toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER); + + // Get the audit + restAuditMockMvc.perform(get("/management/audits?fromDate="+fromDate+"&toDate="+toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); + } + + @Test + public void getNonExistingAuditsByDate() throws Exception { + // Initialize the database + auditEventRepository.save(auditEvent); + + // Generate dates for selecting audits by date, making sure the period will not contain the sample audit + String fromDate = SAMPLE_TIMESTAMP.minusDays(2).format(FORMATTER); + String toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); + + // Query audits but expect no results + restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" + toDate)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(header().string("X-Total-Count", "0")); + } + + @Test + public void getNonExistingAudit() throws Exception { + // Get the audit + restAuditMockMvc.perform(get("/management/audits/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/CommentResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/CommentResourceIntTest.java new file mode 100644 index 0000000000..04b16b25f8 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/CommentResourceIntTest.java @@ -0,0 +1,279 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; + +import com.baeldung.domain.Comment; +import com.baeldung.domain.Post; +import com.baeldung.repository.CommentRepository; +import com.baeldung.web.rest.errors.ExceptionTranslator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the CommentResource REST controller. + * + * @see CommentResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class CommentResourceIntTest { + + private static final String DEFAULT_TEXT = "AAAAAAAAAA"; + private static final String UPDATED_TEXT = "BBBBBBBBBB"; + + private static final LocalDate DEFAULT_CREATION_DATE = LocalDate.ofEpochDay(0L); + private static final LocalDate UPDATED_CREATION_DATE = LocalDate.now(ZoneId.systemDefault()); + + @Autowired + private CommentRepository commentRepository; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + private MockMvc restCommentMockMvc; + + private Comment comment; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + CommentResource commentResource = new CommentResource(commentRepository); + this.restCommentMockMvc = MockMvcBuilders.standaloneSetup(commentResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter).build(); + } + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static Comment createEntity(EntityManager em) { + Comment comment = new Comment() + .text(DEFAULT_TEXT) + .creationDate(DEFAULT_CREATION_DATE); + // Add required entity + Post post = PostResourceIntTest.createEntity(em); + em.persist(post); + em.flush(); + comment.setPost(post); + return comment; + } + + @Before + public void initTest() { + comment = createEntity(em); + } + + @Test + @Transactional + public void createComment() throws Exception { + int databaseSizeBeforeCreate = commentRepository.findAll().size(); + + // Create the Comment + restCommentMockMvc.perform(post("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(comment))) + .andExpect(status().isCreated()); + + // Validate the Comment in the database + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeCreate + 1); + Comment testComment = commentList.get(commentList.size() - 1); + assertThat(testComment.getText()).isEqualTo(DEFAULT_TEXT); + assertThat(testComment.getCreationDate()).isEqualTo(DEFAULT_CREATION_DATE); + } + + @Test + @Transactional + public void createCommentWithExistingId() throws Exception { + int databaseSizeBeforeCreate = commentRepository.findAll().size(); + + // Create the Comment with an existing ID + comment.setId(1L); + + // An entity with an existing ID cannot be created, so this API call must fail + restCommentMockMvc.perform(post("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(comment))) + .andExpect(status().isBadRequest()); + + // Validate the Alice in the database + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void checkTextIsRequired() throws Exception { + int databaseSizeBeforeTest = commentRepository.findAll().size(); + // set the field null + comment.setText(null); + + // Create the Comment, which fails. + + restCommentMockMvc.perform(post("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(comment))) + .andExpect(status().isBadRequest()); + + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkCreationDateIsRequired() throws Exception { + int databaseSizeBeforeTest = commentRepository.findAll().size(); + // set the field null + comment.setCreationDate(null); + + // Create the Comment, which fails. + + restCommentMockMvc.perform(post("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(comment))) + .andExpect(status().isBadRequest()); + + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void getAllComments() throws Exception { + // Initialize the database + commentRepository.saveAndFlush(comment); + + // Get all the commentList + restCommentMockMvc.perform(get("/api/comments?sort=id,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].id").value(hasItem(comment.getId().intValue()))) + .andExpect(jsonPath("$.[*].text").value(hasItem(DEFAULT_TEXT.toString()))) + .andExpect(jsonPath("$.[*].creationDate").value(hasItem(DEFAULT_CREATION_DATE.toString()))); + } + + @Test + @Transactional + public void getComment() throws Exception { + // Initialize the database + commentRepository.saveAndFlush(comment); + + // Get the comment + restCommentMockMvc.perform(get("/api/comments/{id}", comment.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.id").value(comment.getId().intValue())) + .andExpect(jsonPath("$.text").value(DEFAULT_TEXT.toString())) + .andExpect(jsonPath("$.creationDate").value(DEFAULT_CREATION_DATE.toString())); + } + + @Test + @Transactional + public void getNonExistingComment() throws Exception { + // Get the comment + restCommentMockMvc.perform(get("/api/comments/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateComment() throws Exception { + // Initialize the database + commentRepository.saveAndFlush(comment); + int databaseSizeBeforeUpdate = commentRepository.findAll().size(); + + // Update the comment + Comment updatedComment = commentRepository.findOne(comment.getId()); + updatedComment + .text(UPDATED_TEXT) + .creationDate(UPDATED_CREATION_DATE); + + restCommentMockMvc.perform(put("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedComment))) + .andExpect(status().isOk()); + + // Validate the Comment in the database + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeUpdate); + Comment testComment = commentList.get(commentList.size() - 1); + assertThat(testComment.getText()).isEqualTo(UPDATED_TEXT); + assertThat(testComment.getCreationDate()).isEqualTo(UPDATED_CREATION_DATE); + } + + @Test + @Transactional + public void updateNonExistingComment() throws Exception { + int databaseSizeBeforeUpdate = commentRepository.findAll().size(); + + // Create the Comment + + // If the entity doesn't have an ID, it will be created instead of just being updated + restCommentMockMvc.perform(put("/api/comments") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(comment))) + .andExpect(status().isCreated()); + + // Validate the Comment in the database + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeUpdate + 1); + } + + @Test + @Transactional + public void deleteComment() throws Exception { + // Initialize the database + commentRepository.saveAndFlush(comment); + int databaseSizeBeforeDelete = commentRepository.findAll().size(); + + // Get the comment + restCommentMockMvc.perform(delete("/api/comments/{id}", comment.getId()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List commentList = commentRepository.findAll(); + assertThat(commentList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void equalsVerifier() throws Exception { + TestUtil.equalsVerifier(Comment.class); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/LogsResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/LogsResourceIntTest.java new file mode 100644 index 0000000000..92bb976205 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/LogsResourceIntTest.java @@ -0,0 +1,59 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; +import com.baeldung.web.rest.vm.LoggerVM; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the LogsResource REST controller. + * + * @see LogsResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class LogsResourceIntTest { + + private MockMvc restLogsMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + LogsResource logsResource = new LogsResource(); + this.restLogsMockMvc = MockMvcBuilders + .standaloneSetup(logsResource) + .build(); + } + + @Test + public void getAllLogs()throws Exception { + restLogsMockMvc.perform(get("/management/logs")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + @Test + public void changeLogs()throws Exception { + LoggerVM logger = new LoggerVM(); + logger.setLevel("INFO"); + logger.setName("ROOT"); + + restLogsMockMvc.perform(put("/management/logs") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(logger))) + .andExpect(status().isNoContent()); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/PostResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/PostResourceIntTest.java new file mode 100644 index 0000000000..2a23452711 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/PostResourceIntTest.java @@ -0,0 +1,306 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; + +import com.baeldung.domain.Post; +import com.baeldung.domain.User; +import com.baeldung.repository.PostRepository; +import com.baeldung.web.rest.errors.ExceptionTranslator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the PostResource REST controller. + * + * @see PostResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class PostResourceIntTest { + + private static final String DEFAULT_TITLE = "AAAAAAAAAA"; + private static final String UPDATED_TITLE = "BBBBBBBBBB"; + + private static final String DEFAULT_CONTENT = "AAAAAAAAAA"; + private static final String UPDATED_CONTENT = "BBBBBBBBBB"; + + private static final LocalDate DEFAULT_CREATION_DATE = LocalDate.ofEpochDay(0L); + private static final LocalDate UPDATED_CREATION_DATE = LocalDate.now(ZoneId.systemDefault()); + + @Autowired + private PostRepository postRepository; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + private MockMvc restPostMockMvc; + + private Post post; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + PostResource postResource = new PostResource(postRepository); + this.restPostMockMvc = MockMvcBuilders.standaloneSetup(postResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter).build(); + } + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static Post createEntity(EntityManager em) { + Post post = new Post() + .title(DEFAULT_TITLE) + .content(DEFAULT_CONTENT) + .creationDate(DEFAULT_CREATION_DATE); + // Add required entity + User creator = UserResourceIntTest.createEntity(em); + em.persist(creator); + em.flush(); + post.setCreator(creator); + return post; + } + + @Before + public void initTest() { + post = createEntity(em); + } + + @Test + @Transactional + public void createPost() throws Exception { + int databaseSizeBeforeCreate = postRepository.findAll().size(); + + // Create the Post + restPostMockMvc.perform(post("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isCreated()); + + // Validate the Post in the database + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeCreate + 1); + Post testPost = postList.get(postList.size() - 1); + assertThat(testPost.getTitle()).isEqualTo(DEFAULT_TITLE); + assertThat(testPost.getContent()).isEqualTo(DEFAULT_CONTENT); + assertThat(testPost.getCreationDate()).isEqualTo(DEFAULT_CREATION_DATE); + } + + @Test + @Transactional + public void createPostWithExistingId() throws Exception { + int databaseSizeBeforeCreate = postRepository.findAll().size(); + + // Create the Post with an existing ID + post.setId(1L); + + // An entity with an existing ID cannot be created, so this API call must fail + restPostMockMvc.perform(post("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isBadRequest()); + + // Validate the Alice in the database + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void checkTitleIsRequired() throws Exception { + int databaseSizeBeforeTest = postRepository.findAll().size(); + // set the field null + post.setTitle(null); + + // Create the Post, which fails. + + restPostMockMvc.perform(post("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isBadRequest()); + + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkContentIsRequired() throws Exception { + int databaseSizeBeforeTest = postRepository.findAll().size(); + // set the field null + post.setContent(null); + + // Create the Post, which fails. + + restPostMockMvc.perform(post("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isBadRequest()); + + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void checkCreationDateIsRequired() throws Exception { + int databaseSizeBeforeTest = postRepository.findAll().size(); + // set the field null + post.setCreationDate(null); + + // Create the Post, which fails. + + restPostMockMvc.perform(post("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isBadRequest()); + + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeTest); + } + + @Test + @Transactional + public void getAllPosts() throws Exception { + // Initialize the database + postRepository.saveAndFlush(post); + + // Get all the postList + restPostMockMvc.perform(get("/api/posts?sort=id,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].id").value(hasItem(post.getId().intValue()))) + .andExpect(jsonPath("$.[*].title").value(hasItem(DEFAULT_TITLE.toString()))) + .andExpect(jsonPath("$.[*].content").value(hasItem(DEFAULT_CONTENT.toString()))) + .andExpect(jsonPath("$.[*].creationDate").value(hasItem(DEFAULT_CREATION_DATE.toString()))); + } + + @Test + @Transactional + public void getPost() throws Exception { + // Initialize the database + postRepository.saveAndFlush(post); + + // Get the post + restPostMockMvc.perform(get("/api/posts/{id}", post.getId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.id").value(post.getId().intValue())) + .andExpect(jsonPath("$.title").value(DEFAULT_TITLE.toString())) + .andExpect(jsonPath("$.content").value(DEFAULT_CONTENT.toString())) + .andExpect(jsonPath("$.creationDate").value(DEFAULT_CREATION_DATE.toString())); + } + + @Test + @Transactional + public void getNonExistingPost() throws Exception { + // Get the post + restPostMockMvc.perform(get("/api/posts/{id}", Long.MAX_VALUE)) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updatePost() throws Exception { + // Initialize the database + postRepository.saveAndFlush(post); + int databaseSizeBeforeUpdate = postRepository.findAll().size(); + + // Update the post + Post updatedPost = postRepository.findOne(post.getId()); + updatedPost + .title(UPDATED_TITLE) + .content(UPDATED_CONTENT) + .creationDate(UPDATED_CREATION_DATE); + + restPostMockMvc.perform(put("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedPost))) + .andExpect(status().isOk()); + + // Validate the Post in the database + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeUpdate); + Post testPost = postList.get(postList.size() - 1); + assertThat(testPost.getTitle()).isEqualTo(UPDATED_TITLE); + assertThat(testPost.getContent()).isEqualTo(UPDATED_CONTENT); + assertThat(testPost.getCreationDate()).isEqualTo(UPDATED_CREATION_DATE); + } + + @Test + @Transactional + public void updateNonExistingPost() throws Exception { + int databaseSizeBeforeUpdate = postRepository.findAll().size(); + + // Create the Post + + // If the entity doesn't have an ID, it will be created instead of just being updated + restPostMockMvc.perform(put("/api/posts") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(post))) + .andExpect(status().isCreated()); + + // Validate the Post in the database + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeUpdate + 1); + } + + @Test + @Transactional + public void deletePost() throws Exception { + // Initialize the database + postRepository.saveAndFlush(post); + int databaseSizeBeforeDelete = postRepository.findAll().size(); + + // Get the post + restPostMockMvc.perform(delete("/api/posts/{id}", post.getId()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List postList = postRepository.findAll(); + assertThat(postList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void equalsVerifier() throws Exception { + TestUtil.equalsVerifier(Post.class); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/ProfileInfoResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/ProfileInfoResourceIntTest.java new file mode 100644 index 0000000000..df3544f344 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/ProfileInfoResourceIntTest.java @@ -0,0 +1,86 @@ +package com.baeldung.web.rest; + +import io.github.jhipster.config.JHipsterProperties; +import com.baeldung.BaeldungApp; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.env.Environment; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Test class for the ProfileInfoResource REST controller. + * + * @see ProfileInfoResource + **/ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class ProfileInfoResourceIntTest { + + @Mock + private Environment environment; + + @Mock + private JHipsterProperties jHipsterProperties; + + private MockMvc restProfileMockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + String mockProfile[] = {"test"}; + JHipsterProperties.Ribbon ribbon = new JHipsterProperties.Ribbon(); + ribbon.setDisplayOnActiveProfiles(mockProfile); + when(jHipsterProperties.getRibbon()).thenReturn(ribbon); + + String activeProfiles[] = {"test"}; + when(environment.getDefaultProfiles()).thenReturn(activeProfiles); + when(environment.getActiveProfiles()).thenReturn(activeProfiles); + + ProfileInfoResource profileInfoResource = new ProfileInfoResource(environment, jHipsterProperties); + this.restProfileMockMvc = MockMvcBuilders + .standaloneSetup(profileInfoResource) + .build(); + } + + @Test + public void getProfileInfoWithRibbon() throws Exception { + restProfileMockMvc.perform(get("/api/profile-info")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + @Test + public void getProfileInfoWithoutRibbon() throws Exception { + JHipsterProperties.Ribbon ribbon = new JHipsterProperties.Ribbon(); + ribbon.setDisplayOnActiveProfiles(null); + when(jHipsterProperties.getRibbon()).thenReturn(ribbon); + + restProfileMockMvc.perform(get("/api/profile-info")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + @Test + public void getProfileInfoWithoutActiveProfiles() throws Exception { + String emptyProfile[] = {}; + when(environment.getDefaultProfiles()).thenReturn(emptyProfile); + when(environment.getActiveProfiles()).thenReturn(emptyProfile); + + restProfileMockMvc.perform(get("/api/profile-info")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/TestUtil.java b/jhipster/src/test/java/com/baeldung/web/rest/TestUtil.java new file mode 100644 index 0000000000..64d092fdf1 --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/TestUtil.java @@ -0,0 +1,120 @@ +package com.baeldung.web.rest; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.http.MediaType; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utility class for testing REST controllers. + */ +public class TestUtil { + + /** MediaType for JSON UTF8 */ + public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( + MediaType.APPLICATION_JSON.getType(), + MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + /** + * Convert an object to JSON byte array. + * + * @param object + * the object to convert + * @return the JSON byte array + * @throws IOException + */ + public static byte[] convertObjectToJsonBytes(Object object) + throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + JavaTimeModule module = new JavaTimeModule(); + mapper.registerModule(module); + + return mapper.writeValueAsBytes(object); + } + + /** + * Create a byte array with a specific size filled with specified data. + * + * @param size the size of the byte array + * @param data the data to put in the byte array + * @return the JSON byte array + */ + public static byte[] createByteArray(int size, String data) { + byte[] byteArray = new byte[size]; + for (int i = 0; i < size; i++) { + byteArray[i] = Byte.parseByte(data, 2); + } + return byteArray; + } + + /** + * A matcher that tests that the examined string represents the same instant as the reference datetime. + */ + public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { + + private final ZonedDateTime date; + + public ZonedDateTimeMatcher(ZonedDateTime date) { + this.date = date; + } + + @Override + protected boolean matchesSafely(String item, Description mismatchDescription) { + try { + if (!date.isEqual(ZonedDateTime.parse(item))) { + mismatchDescription.appendText("was ").appendValue(item); + return false; + } + return true; + } catch (DateTimeParseException e) { + mismatchDescription.appendText("was ").appendValue(item) + .appendText(", which could not be parsed as a ZonedDateTime"); + return false; + } + + } + + @Override + public void describeTo(Description description) { + description.appendText("a String representing the same Instant as ").appendValue(date); + } + } + + /** + * Creates a matcher that matches when the examined string reprensents the same instant as the reference datetime + * @param date the reference datetime against which the examined string is checked + */ + public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { + return new ZonedDateTimeMatcher(date); + } + + /** + * Verifies the equals/hashcode contract on the domain object. + */ + public static void equalsVerifier(Class clazz) throws Exception { + Object domainObject1 = clazz.getConstructor().newInstance(); + assertThat(domainObject1.toString()).isNotNull(); + assertThat(domainObject1).isEqualTo(domainObject1); + assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); + // Test with an instance of another class + Object testOtherObject = new Object(); + assertThat(domainObject1).isNotEqualTo(testOtherObject); + // Test with an instance of the same class + Object domainObject2 = clazz.getConstructor().newInstance(); + assertThat(domainObject1).isNotEqualTo(domainObject2); + // HashCodes are equals because the objects are not persisted yet + assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); + } +} diff --git a/jhipster/src/test/java/com/baeldung/web/rest/UserResourceIntTest.java b/jhipster/src/test/java/com/baeldung/web/rest/UserResourceIntTest.java new file mode 100644 index 0000000000..74df23283a --- /dev/null +++ b/jhipster/src/test/java/com/baeldung/web/rest/UserResourceIntTest.java @@ -0,0 +1,522 @@ +package com.baeldung.web.rest; + +import com.baeldung.BaeldungApp; +import com.baeldung.domain.User; +import com.baeldung.repository.UserRepository; +import com.baeldung.service.MailService; +import com.baeldung.service.UserService; +import com.baeldung.web.rest.errors.ExceptionTranslator; +import com.baeldung.web.rest.vm.ManagedUserVM; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +/** + * Test class for the UserResource REST controller. + * + * @see UserResource + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = BaeldungApp.class) +public class UserResourceIntTest { + + private static final String DEFAULT_LOGIN = "johndoe"; + private static final String UPDATED_LOGIN = "jhipster"; + + private static final String DEFAULT_PASSWORD = "passjohndoe"; + private static final String UPDATED_PASSWORD = "passjhipster"; + + private static final String DEFAULT_EMAIL = "johndoe@localhost"; + private static final String UPDATED_EMAIL = "jhipster@localhost"; + + private static final String DEFAULT_FIRSTNAME = "john"; + private static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; + + private static final String DEFAULT_LASTNAME = "doe"; + private static final String UPDATED_LASTNAME = "jhipsterLastName"; + + private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50"; + private static final String UPDATED_IMAGEURL = "http://placehold.it/40x40"; + + private static final String DEFAULT_LANGKEY = "en"; + private static final String UPDATED_LANGKEY = "fr"; + + @Autowired + private UserRepository userRepository; + + @Autowired + private MailService mailService; + + @Autowired + private UserService userService; + + @Autowired + private MappingJackson2HttpMessageConverter jacksonMessageConverter; + + @Autowired + private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + + @Autowired + private ExceptionTranslator exceptionTranslator; + + @Autowired + private EntityManager em; + + private MockMvc restUserMockMvc; + + private User user; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + UserResource userResource = new UserResource(userRepository, mailService, userService); + this.restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .build(); + } + + /** + * Create a User. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which has a required relationship to the User entity. + */ + public static User createEntity(EntityManager em) { + User user = new User(); + user.setLogin(DEFAULT_LOGIN); + user.setPassword(RandomStringUtils.random(60)); + user.setActivated(true); + user.setEmail(DEFAULT_EMAIL); + user.setFirstName(DEFAULT_FIRSTNAME); + user.setLastName(DEFAULT_LASTNAME); + user.setImageUrl(DEFAULT_IMAGEURL); + user.setLangKey(DEFAULT_LANGKEY); + return user; + } + + @Before + public void initTest() { + user = createEntity(em); + } + + @Test + @Transactional + public void createUser() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + // Create the User + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + null, + DEFAULT_LOGIN, + DEFAULT_PASSWORD, + DEFAULT_FIRSTNAME, + DEFAULT_LASTNAME, + DEFAULT_EMAIL, + true, + DEFAULT_IMAGEURL, + DEFAULT_LANGKEY, + null, + null, + null, + null, + autorities); + + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isCreated()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + } + + @Test + @Transactional + public void createUserWithExistingId() throws Exception { + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + 1L, + DEFAULT_LOGIN, + DEFAULT_PASSWORD, + DEFAULT_FIRSTNAME, + DEFAULT_LASTNAME, + DEFAULT_EMAIL, + true, + DEFAULT_IMAGEURL, + DEFAULT_LANGKEY, + null, + null, + null, + null, + autorities); + + // An entity with an existing ID cannot be created, so this API call must fail + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + null, + DEFAULT_LOGIN, // this login should already be used + DEFAULT_PASSWORD, + DEFAULT_FIRSTNAME, + DEFAULT_LASTNAME, + "anothermail@localhost", + true, + DEFAULT_IMAGEURL, + DEFAULT_LANGKEY, + null, + null, + null, + null, + autorities); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void createUserWithExistingEmail() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeCreate = userRepository.findAll().size(); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + null, + "anotherlogin", + DEFAULT_PASSWORD, + DEFAULT_FIRSTNAME, + DEFAULT_LASTNAME, + DEFAULT_EMAIL, // this email should already be used + true, + DEFAULT_IMAGEURL, + DEFAULT_LANGKEY, + null, + null, + null, + null, + autorities); + + // Create the User + restUserMockMvc.perform(post("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeCreate); + } + + @Test + @Transactional + public void getAllUsers() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get all the users + restUserMockMvc.perform(get("/api/users?sort=id,desc") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) + .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) + .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) + .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) + .andExpect(jsonPath("$.[*].imageUrl").value(hasItem(DEFAULT_IMAGEURL))) + .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); + } + + @Test + @Transactional + public void getUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + // Get the user + restUserMockMvc.perform(get("/api/users/{login}", user.getLogin())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.login").value(user.getLogin())) + .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) + .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) + .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) + .andExpect(jsonPath("$.imageUrl").value(DEFAULT_IMAGEURL)) + .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); + } + + @Test + @Transactional + public void getNonExistingUser() throws Exception { + restUserMockMvc.perform(get("/api/users/unknown")) + .andExpect(status().isNotFound()); + } + + @Test + @Transactional + public void updateUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findOne(user.getId()); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + updatedUser.getId(), + updatedUser.getLogin(), + UPDATED_PASSWORD, + UPDATED_FIRSTNAME, + UPDATED_LASTNAME, + UPDATED_EMAIL, + updatedUser.getActivated(), + UPDATED_IMAGEURL, + UPDATED_LANGKEY, + updatedUser.getCreatedBy(), + updatedUser.getCreatedDate(), + updatedUser.getLastModifiedBy(), + updatedUser.getLastModifiedDate(), + autorities); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findOne(user.getId()); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + updatedUser.getId(), + UPDATED_LOGIN, + UPDATED_PASSWORD, + UPDATED_FIRSTNAME, + UPDATED_LASTNAME, + UPDATED_EMAIL, + updatedUser.getActivated(), + UPDATED_IMAGEURL, + UPDATED_LANGKEY, + updatedUser.getCreatedBy(), + updatedUser.getCreatedDate(), + updatedUser.getLastModifiedBy(), + updatedUser.getLastModifiedDate(), + autorities); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isOk()); + + // Validate the User in the database + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeUpdate); + User testUser = userList.get(userList.size() - 1); + assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN); + assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL); + assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + } + + @Test + @Transactional + public void updateUserExistingEmail() throws Exception { + // Initialize the database with 2 users + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findOne(user.getId()); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + updatedUser.getId(), + updatedUser.getLogin(), + updatedUser.getPassword(), + updatedUser.getFirstName(), + updatedUser.getLastName(), + "jhipster@localhost", // this email should already be used by anotherUser + updatedUser.getActivated(), + updatedUser.getImageUrl(), + updatedUser.getLangKey(), + updatedUser.getCreatedBy(), + updatedUser.getCreatedDate(), + updatedUser.getLastModifiedBy(), + updatedUser.getLastModifiedDate(), + autorities); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void updateUserExistingLogin() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + + User anotherUser = new User(); + anotherUser.setLogin("jhipster"); + anotherUser.setPassword(RandomStringUtils.random(60)); + anotherUser.setActivated(true); + anotherUser.setEmail("jhipster@localhost"); + anotherUser.setFirstName("java"); + anotherUser.setLastName("hipster"); + anotherUser.setImageUrl(""); + anotherUser.setLangKey("en"); + userRepository.saveAndFlush(anotherUser); + int databaseSizeBeforeUpdate = userRepository.findAll().size(); + + // Update the user + User updatedUser = userRepository.findOne(user.getId()); + + Set autorities = new HashSet<>(); + autorities.add("ROLE_USER"); + ManagedUserVM managedUserVM = new ManagedUserVM( + updatedUser.getId(), + "jhipster", // this login should already be used by anotherUser + updatedUser.getPassword(), + updatedUser.getFirstName(), + updatedUser.getLastName(), + updatedUser.getEmail(), + updatedUser.getActivated(), + updatedUser.getImageUrl(), + updatedUser.getLangKey(), + updatedUser.getCreatedBy(), + updatedUser.getCreatedDate(), + updatedUser.getLastModifiedBy(), + updatedUser.getLastModifiedDate(), + autorities); + + restUserMockMvc.perform(put("/api/users") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(managedUserVM))) + .andExpect(status().isBadRequest()); + } + + @Test + @Transactional + public void deleteUser() throws Exception { + // Initialize the database + userRepository.saveAndFlush(user); + int databaseSizeBeforeDelete = userRepository.findAll().size(); + + // Delete the user + restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin()) + .accept(TestUtil.APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + + // Validate the database is empty + List userList = userRepository.findAll(); + assertThat(userList).hasSize(databaseSizeBeforeDelete - 1); + } + + @Test + @Transactional + public void equalsVerifier() throws Exception { + User userA = new User(); + userA.setLogin("AAA"); + User userB = new User(); + userB.setLogin("BBB"); + assertThat(userA).isNotEqualTo(userB); + } +} diff --git a/jhipster/src/test/javascript/e2e/account/account.spec.ts b/jhipster/src/test/javascript/e2e/account/account.spec.ts new file mode 100644 index 0000000000..cfa9fae078 --- /dev/null +++ b/jhipster/src/test/javascript/e2e/account/account.spec.ts @@ -0,0 +1,108 @@ +import { browser, element, by, $ } from 'protractor'; + +describe('account', () => { + + const username = element(by.id('username')); + const password = element(by.id('password')); + const accountMenu = element(by.id('account-menu')); + const login = element(by.id('login')); + const logout = element(by.id('logout')); + + beforeAll(() => { + browser.get('/'); + }); + + it('should fail to login with bad password', () => { + const expect1 = /home.title/; + element.all(by.css('h1')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + accountMenu.click(); + login.click(); + + username.sendKeys('admin'); + password.sendKeys('foo'); + element(by.css('button[type=submit]')).click(); + + const expect2 = /login.messages.error.authentication/; + element.all(by.css('.alert-danger')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect2); + }); + }); + + it('should login successfully with admin account', () => { + const expect1 = /login.title/; + element.all(by.css('.modal-content h1')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + username.clear(); + username.sendKeys('admin'); + password.clear(); + password.sendKeys('admin'); + element(by.css('button[type=submit]')).click(); + + browser.waitForAngular(); + + const expect2 = /home.logged.message/; + element.all(by.css('.alert-success span')).getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect2); + }); + }); + + it('should be able to update settings', () => { + accountMenu.click(); + element(by.css('[routerLink="settings"]')).click(); + + const expect1 = /settings.title/; + element.all(by.css('h2')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + element(by.css('button[type=submit]')).click(); + + const expect2 = /settings.messages.success/; + element.all(by.css('.alert-success')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect2); + }); + }); + + it('should be able to update password', () => { + accountMenu.click(); + element(by.css('[routerLink="password"]')).click(); + + const expect1 = /password.title/; + element.all(by.css('h2')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + password.sendKeys('newpassword'); + element(by.id('confirmPassword')).sendKeys('newpassword'); + element(by.css('button[type=submit]')).click(); + + const expect2 = /password.messages.success/; + element.all(by.css('.alert-success')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect2); + }); + accountMenu.click(); + logout.click(); + + accountMenu.click(); + login.click(); + + username.sendKeys('admin'); + password.sendKeys('newpassword'); + element(by.css('button[type=submit]')).click(); + + accountMenu.click(); + element(by.css('[routerLink="password"]')).click(); + // change back to default + password.clear(); + password.sendKeys('admin'); + element(by.id('confirmPassword')).clear(); + element(by.id('confirmPassword')).sendKeys('admin'); + element(by.css('button[type=submit]')).click(); + }); + + afterAll(() => { + accountMenu.click(); + logout.click(); + }); +}); diff --git a/jhipster/src/test/javascript/e2e/admin/administration.spec.ts b/jhipster/src/test/javascript/e2e/admin/administration.spec.ts new file mode 100644 index 0000000000..0516f7a27d --- /dev/null +++ b/jhipster/src/test/javascript/e2e/admin/administration.spec.ts @@ -0,0 +1,80 @@ +import { browser, element, by, $ } from 'protractor'; + +describe('administration', () => { + + const username = element(by.id('username')); + const password = element(by.id('password')); + const accountMenu = element(by.id('account-menu')); + const adminMenu = element(by.id('admin-menu')); + const login = element(by.id('login')); + const logout = element(by.id('logout')); + + beforeAll(() => { + browser.get('/'); + + accountMenu.click(); + login.click(); + + username.sendKeys('admin'); + password.sendKeys('admin'); + element(by.css('button[type=submit]')).click(); + browser.waitForAngular(); + }); + + beforeEach(() => { + adminMenu.click(); + }); + + it('should load user management', () => { + element(by.css('[routerLink="user-management"]')).click(); + const expect1 = /userManagement.home.title/; + element.all(by.css('h2 span')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + it('should load metrics', () => { + element(by.css('[routerLink="jhi-metrics"]')).click(); + const expect1 = /metrics.title/; + element.all(by.css('h2 span')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + it('should load health', () => { + element(by.css('[routerLink="jhi-health"]')).click(); + const expect1 = /health.title/; + element.all(by.css('h2 span')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + it('should load configuration', () => { + element(by.css('[routerLink="jhi-configuration"]')).click(); + const expect1 = /configuration.title/; + element.all(by.css('h2')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + it('should load audits', () => { + element(by.css('[routerLink="audits"]')).click(); + const expect1 = /audits.title/; + element.all(by.css('h2')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + it('should load logs', () => { + element(by.css('[routerLink="logs"]')).click(); + const expect1 = /logs.title/; + element.all(by.css('h2')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expect1); + }); + }); + + afterAll(() => { + accountMenu.click(); + logout.click(); + }); +}); diff --git a/jhipster/src/test/javascript/e2e/entities/comment.spec.ts b/jhipster/src/test/javascript/e2e/entities/comment.spec.ts new file mode 100644 index 0000000000..3032bd1364 --- /dev/null +++ b/jhipster/src/test/javascript/e2e/entities/comment.spec.ts @@ -0,0 +1,49 @@ +import { browser, element, by, $ } from 'protractor'; + +describe('Comment e2e test', () => { + + const username = element(by.id('username')); + const password = element(by.id('password')); + const entityMenu = element(by.id('entity-menu')); + const accountMenu = element(by.id('account-menu')); + const login = element(by.id('login')); + const logout = element(by.id('logout')); + + beforeAll(() => { + browser.get('/'); + + accountMenu.click(); + login.click(); + + username.sendKeys('admin'); + password.sendKeys('admin'); + element(by.css('button[type=submit]')).click(); + browser.waitForAngular(); + }); + + it('should load Comments', () => { + entityMenu.click(); + element.all(by.css('[routerLink="comment"]')).first().click().then(() => { + const expectVal = /baeldungApp.comment.home.title/; + element.all(by.css('h2 span')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expectVal); + }); + }); + }); + + it('should load create Comment dialog', function () { + element(by.css('button.create-comment')).click().then(() => { + const expectVal = /baeldungApp.comment.home.createOrEditLabel/; + element.all(by.css('h4.modal-title')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expectVal); + }); + + element(by.css('button.close')).click(); + }); + }); + + afterAll(function () { + accountMenu.click(); + logout.click(); + }); +}); diff --git a/jhipster/src/test/javascript/e2e/entities/post.spec.ts b/jhipster/src/test/javascript/e2e/entities/post.spec.ts new file mode 100644 index 0000000000..3c8d04f731 --- /dev/null +++ b/jhipster/src/test/javascript/e2e/entities/post.spec.ts @@ -0,0 +1,49 @@ +import { browser, element, by, $ } from 'protractor'; + +describe('Post e2e test', () => { + + const username = element(by.id('username')); + const password = element(by.id('password')); + const entityMenu = element(by.id('entity-menu')); + const accountMenu = element(by.id('account-menu')); + const login = element(by.id('login')); + const logout = element(by.id('logout')); + + beforeAll(() => { + browser.get('/'); + + accountMenu.click(); + login.click(); + + username.sendKeys('admin'); + password.sendKeys('admin'); + element(by.css('button[type=submit]')).click(); + browser.waitForAngular(); + }); + + it('should load Posts', () => { + entityMenu.click(); + element.all(by.css('[routerLink="post"]')).first().click().then(() => { + const expectVal = /baeldungApp.post.home.title/; + element.all(by.css('h2 span')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expectVal); + }); + }); + }); + + it('should load create Post dialog', function () { + element(by.css('button.create-post')).click().then(() => { + const expectVal = /baeldungApp.post.home.createOrEditLabel/; + element.all(by.css('h4.modal-title')).first().getAttribute('jhiTranslate').then((value) => { + expect(value).toMatch(expectVal); + }); + + element(by.css('button.close')).click(); + }); + }); + + afterAll(function () { + accountMenu.click(); + logout.click(); + }); +}); diff --git a/jhipster/src/test/javascript/karma.conf.js b/jhipster/src/test/javascript/karma.conf.js new file mode 100644 index 0000000000..1b10226955 --- /dev/null +++ b/jhipster/src/test/javascript/karma.conf.js @@ -0,0 +1,126 @@ +'use strict'; + +const path = require('path'); +const webpack = require('webpack'); +const WATCH = process.argv.indexOf('--watch') > -1; +const LoaderOptionsPlugin = require("webpack/lib/LoaderOptionsPlugin"); + +module.exports = function (config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: './', + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine', 'intl-shim'], + + // list of files / patterns to load in the browser + files: [ + 'spec/entry.ts' + ], + + + // list of files to exclude + exclude: ['e2e/**'], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'spec/entry.ts': ['webpack', 'sourcemap'] + }, + + webpack: { + resolve: { + extensions: ['.ts', '.js'] + }, + module: { + rules: [ + { + test: /\.ts$/, enforce: 'pre', loader: 'tslint-loader', exclude: /(test|node_modules)/ + }, + { + test: /\.ts$/, + loaders: ['awesome-typescript-loader', 'angular2-template-loader?keepUrl=true'], + exclude: /node_modules/ + }, + { + test: /\.(html|css)$/, + loader: 'raw-loader', + exclude: /\.async\.(html|css)$/ + }, + { + test: /\.async\.(html|css)$/, + loaders: ['file?name=[name].[hash].[ext]', 'extract'] + }, + { + test: /\.scss$/, + loaders: ['to-string-loader', 'css-loader', 'sass-loader'] + }, + { + test: /src\/main\/webapp\/.+\.ts$/, + enforce: 'post', + exclude: /(test|node_modules)/, + loader: 'sourcemap-istanbul-instrumenter-loader?force-sourcemap=true' + }] + }, + devtool: 'inline-source-map', + plugins: [ + new webpack.ContextReplacementPlugin( + // The (\\|\/) piece accounts for path separators in *nix and Windows + /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, + root('./src') // location of your src + ), + new LoaderOptionsPlugin({ + options: { + tslint: { + emitErrors: !WATCH, + failOnHint: false + } + } + }) + ] + }, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['dots', 'junit', 'progress', 'karma-remap-istanbul'], + + junitReporter: { + outputFile: '../../../../target/test-results/karma/TESTS-results.xml' + }, + + remapIstanbulReporter: { + reports: { // eslint-disable-line + 'html': 'target/test-results/coverage', + 'text-summary': null + } + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: WATCH, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: !WATCH + }); +}; + +function root(__path) { + return path.join(__dirname, __path); +} diff --git a/jhipster/src/test/javascript/protractor.conf.js b/jhipster/src/test/javascript/protractor.conf.js new file mode 100644 index 0000000000..e79b09e17b --- /dev/null +++ b/jhipster/src/test/javascript/protractor.conf.js @@ -0,0 +1,48 @@ +var HtmlScreenshotReporter = require("protractor-jasmine2-screenshot-reporter"); +var JasmineReporters = require('jasmine-reporters'); + +exports.config = { + allScriptsTimeout: 20000, + + specs: [ + './e2e/account/*.spec.ts', + './e2e/admin/*.spec.ts', + './e2e/entities/*.spec.ts' + ], + + capabilities: { + 'browserName': 'chrome', + 'phantomjs.binary.path': require('phantomjs-prebuilt').path, + 'phantomjs.ghostdriver.cli.args': ['--loglevel=DEBUG'] + }, + + directConnect: true, + + baseUrl: 'http://localhost:8080/', + + framework: 'jasmine2', + + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000 + }, + + beforeLaunch: function() { + require('ts-node').register({ + project: '' + }); + }, + + onPrepare: function() { + browser.driver.manage().window().setSize(1280, 1024); + jasmine.getEnv().addReporter(new JasmineReporters.JUnitXmlReporter({ + savePath: 'target/reports/e2e', + consolidateAll: false + })); + jasmine.getEnv().addReporter(new HtmlScreenshotReporter({ + dest: "target/reports/e2e/screenshots" + })); + }, + + useAllAngular2AppRoots: true +}; diff --git a/jhipster/src/test/javascript/spec/app/account/activate/activate.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/activate/activate.component.spec.ts new file mode 100644 index 0000000000..76a6e9f941 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/activate/activate.component.spec.ts @@ -0,0 +1,84 @@ +import { TestBed, async, tick, fakeAsync, inject } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { BaeldungTestModule } from '../../../test.module'; +import { MockActivatedRoute } from '../../../helpers/mock-route.service'; +import { LoginModalService } from '../../../../../../main/webapp/app/shared'; +import { Activate } from '../../../../../../main/webapp/app/account/activate/activate.service'; +import { ActivateComponent } from '../../../../../../main/webapp/app/account/activate/activate.component'; + +describe('Component Tests', () => { + + describe('ActivateComponent', () => { + + let comp: ActivateComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [ActivateComponent], + providers: [ + Activate, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({'key': 'ABC123'}) + }, + { + provide: LoginModalService, + useValue: null + } + ] + }).overrideComponent(ActivateComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + let fixture = TestBed.createComponent(ActivateComponent); + comp = fixture.componentInstance; + }); + + it('calls activate.get with the key from params', + inject([Activate], + fakeAsync((service: Activate) => { + spyOn(service, 'get').and.returnValue(Observable.of()); + + comp.ngOnInit(); + tick(); + + expect(service.get).toHaveBeenCalledWith('ABC123'); + }) + ) + ); + + it('should set set success to OK upon successful activation', + inject([Activate], + fakeAsync((service: Activate) => { + spyOn(service, 'get').and.returnValue(Observable.of({})); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe(null); + expect(comp.success).toEqual('OK'); + }) + ) + ); + + it('should set set error to ERROR upon activation failure', + inject([Activate], + fakeAsync((service: Activate) => { + spyOn(service, 'get').and.returnValue(Observable.throw('ERROR')); + + comp.ngOnInit(); + tick(); + + expect(comp.error).toBe('ERROR'); + expect(comp.success).toEqual(null); + }) + ) + ); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts new file mode 100644 index 0000000000..537c58351e --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/password-reset/finish/password-reset-finish.component.spec.ts @@ -0,0 +1,79 @@ +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; +import { Renderer, ElementRef } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { LoginModalService } from '../../../../../../../main/webapp/app/shared'; +import { Observable } from 'rxjs/Rx'; +import { BaeldungTestModule } from '../../../../test.module'; +import { PasswordResetFinishComponent } from '../../../../../../../main/webapp/app/account/password-reset/finish/password-reset-finish.component'; +import { PasswordResetFinish } from '../../../../../../../main/webapp/app/account/password-reset/finish/password-reset-finish.service'; +import { MockActivatedRoute } from '../../../../helpers/mock-route.service'; + + +describe('Component Tests', () => { + + describe('PasswordResetFinishComponent', () => { + + let fixture: ComponentFixture; + let comp: PasswordResetFinishComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [PasswordResetFinishComponent], + providers: [ + PasswordResetFinish, + { + provide: LoginModalService, + useValue: null + }, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({'key': 'XYZPDQ'}) + }, + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }).overrideComponent(PasswordResetFinishComponent, { + set: { + template: '' + } + }).createComponent(PasswordResetFinishComponent); + comp = fixture.componentInstance; + }); + + it('should define its initial state', function () { + comp.ngOnInit(); + + expect(comp.keyMissing).toBeFalsy(); + expect(comp.key).toEqual('XYZPDQ'); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', + inject([ElementRef], (elementRef: ElementRef) => { + let element = fixture.nativeElement; + let node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#password'); + expect(node.focus).toHaveBeenCalled(); + }) + ); + + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts new file mode 100644 index 0000000000..55c0a81922 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/password-reset/init/password-reset-init.component.spec.ts @@ -0,0 +1,115 @@ +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; +import { Renderer, ElementRef } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; +import { BaeldungTestModule } from '../../../../test.module'; +import { PasswordResetInitComponent } from '../../../../../../../main/webapp/app/account/password-reset/init/password-reset-init.component'; +import { PasswordResetInit } from '../../../../../../../main/webapp/app/account/password-reset/init/password-reset-init.service'; + + +describe('Component Tests', () => { + + describe('PasswordResetInitComponent', function () { + let fixture: ComponentFixture; + let comp: PasswordResetInitComponent; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [PasswordResetInitComponent], + providers: [ + PasswordResetInit, + { + provide: Renderer, + useValue: { + invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {} + } + }, + { + provide: ElementRef, + useValue: new ElementRef(null) + } + ] + }).overrideComponent(PasswordResetInitComponent, { + set: { + template: '' + } + }).createComponent(PasswordResetInitComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should define its initial state', function () { + expect(comp.success).toBeUndefined(); + expect(comp.error).toBeUndefined(); + expect(comp.errorEmailNotExists).toBeUndefined(); + expect(comp.resetAccount).toEqual({}); + }); + + it('sets focus after the view has been initialized', + inject([ElementRef], (elementRef: ElementRef) => { + let element = fixture.nativeElement; + let node = { + focus() {} + }; + + elementRef.nativeElement = element; + spyOn(element, 'querySelector').and.returnValue(node); + spyOn(node, 'focus'); + + comp.ngAfterViewInit(); + + expect(element.querySelector).toHaveBeenCalledWith('#email'); + expect(node.focus).toHaveBeenCalled(); + }) + ); + + it('notifies of success upon successful requestReset', + inject([PasswordResetInit], (service: PasswordResetInit) => { + spyOn(service, 'save').and.returnValue(Observable.of({})); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toEqual('OK'); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + }) + ); + + it('notifies of unknown email upon e-mail address not registered/400', + inject([PasswordResetInit], (service: PasswordResetInit) => { + spyOn(service, 'save').and.returnValue(Observable.throw({ + status: 400, + data: 'e-mail address not registered' + })); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.errorEmailNotExists).toEqual('ERROR'); + }) + ); + + it('notifies of error upon error response', + inject([PasswordResetInit], (service: PasswordResetInit) => { + spyOn(service, 'save').and.returnValue(Observable.throw({ + status: 503, + data: 'something else' + })); + comp.resetAccount.email = 'user@domain.com'; + + comp.requestReset(); + + expect(service.save).toHaveBeenCalledWith('user@domain.com'); + expect(comp.success).toBeNull(); + expect(comp.errorEmailNotExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + ); + + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts new file mode 100644 index 0000000000..9cdc55529c --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/password/password-strength-bar.component.spec.ts @@ -0,0 +1,53 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; + +import { PasswordStrengthBarComponent } from '../../../../../../main/webapp/app/account/password/password-strength-bar.component'; + +describe('Component Tests', () => { + + describe('PasswordStrengthBarComponent', () => { + + let comp: PasswordStrengthBarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PasswordStrengthBarComponent] + }).overrideComponent(PasswordStrengthBarComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordStrengthBarComponent); + comp = fixture.componentInstance; + }); + + describe('PasswordStrengthBarComponents', () => { + it('should initialize with default values', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.colors).toEqual(['#F00', '#F90', '#FF0', '#9F0', '#0F0']); + expect(comp.getColor(0).idx).toBe(1); + expect(comp.getColor(0).col).toBe(comp.colors[0]); + }); + + it('should increase strength upon password value change', () => { + expect(comp.measureStrength('')).toBe(0); + expect(comp.measureStrength('aa')).toBeGreaterThanOrEqual(comp.measureStrength('')); + expect(comp.measureStrength('aa^6')).toBeGreaterThanOrEqual(comp.measureStrength('aa')); + expect(comp.measureStrength('Aa090(**)')).toBeGreaterThanOrEqual(comp.measureStrength('aa^6')); + expect(comp.measureStrength('Aa090(**)+-07365')).toBeGreaterThanOrEqual(comp.measureStrength('Aa090(**)')); + }); + + it('should change the color based on strength', () => { + expect(comp.getColor(0).col).toBe(comp.colors[0]); + expect(comp.getColor(11).col).toBe(comp.colors[1]); + expect(comp.getColor(22).col).toBe(comp.colors[2]); + expect(comp.getColor(33).col).toBe(comp.colors[3]); + expect(comp.getColor(44).col).toBe(comp.colors[4]); + }); + }); + }); +}); + diff --git a/jhipster/src/test/javascript/spec/app/account/password/password.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/password/password.component.spec.ts new file mode 100644 index 0000000000..e6f4983785 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/password/password.component.spec.ts @@ -0,0 +1,92 @@ +import { ComponentFixture, TestBed, async, inject } from '@angular/core/testing'; +import { Observable } from 'rxjs/Rx'; +import { BaeldungTestModule } from '../../../test.module'; +import { PasswordComponent } from '../../../../../../main/webapp/app/account/password/password.component'; +import { Password } from '../../../../../../main/webapp/app/account/password/password.service'; +import { Principal } from '../../../../../../main/webapp/app/shared/auth/principal.service'; +import { AccountService } from '../../../../../../main/webapp/app/shared/auth/account.service'; + + +describe('Component Tests', () => { + + describe('PasswordComponent', () => { + + let comp: PasswordComponent; + let fixture: ComponentFixture; + let service: Password; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [PasswordComponent], + providers: [ + Principal, + AccountService, + Password + ] + }).overrideComponent(PasswordComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PasswordComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(Password); + }); + + it('should show error if passwords do not match', () => { + // GIVEN + comp.password = 'password1'; + comp.confirmPassword = 'password2'; + // WHEN + comp.changePassword(); + // THEN + expect(comp.doNotMatch).toBe('ERROR'); + expect(comp.error).toBeNull(); + expect(comp.success).toBeNull(); + }); + + it('should call Auth.changePassword when passwords match', () => { + // GIVEN + spyOn(service, 'save').and.returnValue(Observable.of(true)); + comp.password = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(service.save).toHaveBeenCalledWith('myPassword'); + }); + + it('should set success to OK upon success', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(Observable.of(true)); + comp.password = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error if change password fails', function() { + // GIVEN + spyOn(service, 'save').and.returnValue(Observable.throw('ERROR')); + comp.password = comp.confirmPassword = 'myPassword'; + + // WHEN + comp.changePassword(); + + // THEN + expect(comp.doNotMatch).toBeNull(); + expect(comp.success).toBeNull(); + expect(comp.error).toBe('ERROR'); + }); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/account/register/register.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/register/register.component.spec.ts new file mode 100644 index 0000000000..c475c2f3d2 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/register/register.component.spec.ts @@ -0,0 +1,138 @@ +import { ComponentFixture, TestBed, async, inject, tick, fakeAsync } from '@angular/core/testing'; +import { Renderer, ElementRef } from '@angular/core'; +import { Observable } from 'rxjs/Rx'; +import { JhiLanguageService } from 'ng-jhipster'; +import { MockLanguageService } from '../../../helpers/mock-language.service'; +import { BaeldungTestModule } from '../../../test.module'; +import { LoginModalService } from '../../../../../../main/webapp/app/shared'; +import { Register } from '../../../../../../main/webapp/app/account/register/register.service'; +import { RegisterComponent } from '../../../../../../main/webapp/app/account/register/register.component'; + + +describe('Component Tests', () => { + + describe('RegisterComponent', () => { + let fixture: ComponentFixture; + let comp: RegisterComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [RegisterComponent], + providers: [ + Register, + { + provide: LoginModalService, + useValue: null + }, + { + provide: Renderer, + useValue: null + }, + { + provide: ElementRef, + useValue: null + } + ] + }).overrideComponent(RegisterComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RegisterComponent); + comp = fixture.componentInstance; + comp.ngOnInit(); + }); + + it('should ensure the two passwords entered match', function () { + comp.registerAccount.password = 'password'; + comp.confirmPassword = 'non-matching'; + + comp.register(); + + expect(comp.doNotMatch).toEqual('ERROR'); + }); + + it('should update success to OK after creating an account', + inject([Register, JhiLanguageService], + fakeAsync((service: Register, mockTranslate: MockLanguageService) => { + spyOn(service, 'save').and.returnValue(Observable.of({})); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(service.save).toHaveBeenCalledWith({ + password: 'password', + langKey: 'en' + }); + expect(comp.success).toEqual(true); + expect(comp.registerAccount.langKey).toEqual('en'); + expect(mockTranslate.getCurrentSpy).toHaveBeenCalled(); + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + ) + ); + + it('should notify of user existence upon 400/login already in use', + inject([Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue(Observable.throw({ + status: 400, + _body: 'login already in use' + })); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toEqual('ERROR'); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + ) + ); + + it('should notify of email existence upon 400/e-mail address already in use', + inject([Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue(Observable.throw({ + status: 400, + _body: 'e-mail address already in use' + })); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorEmailExists).toEqual('ERROR'); + expect(comp.errorUserExists).toBeNull(); + expect(comp.error).toBeNull(); + }) + ) + ); + + it('should notify of generic error', + inject([Register], + fakeAsync((service: Register) => { + spyOn(service, 'save').and.returnValue(Observable.throw({ + status: 503 + })); + comp.registerAccount.password = comp.confirmPassword = 'password'; + + comp.register(); + tick(); + + expect(comp.errorUserExists).toBeNull(); + expect(comp.errorEmailExists).toBeNull(); + expect(comp.error).toEqual('ERROR'); + }) + ) + ); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/account/settings/settings.component.spec.ts b/jhipster/src/test/javascript/spec/app/account/settings/settings.component.spec.ts new file mode 100644 index 0000000000..266a33be79 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/account/settings/settings.component.spec.ts @@ -0,0 +1,103 @@ +import { ComponentFixture, TestBed, async, inject } from '@angular/core/testing'; +import { Observable } from 'rxjs/Rx'; +import { JhiLanguageHelper } from '../../../../../../main/webapp/app/shared'; +import { BaeldungTestModule } from '../../../test.module'; +import { Principal, AccountService } from '../../../../../../main/webapp/app/shared'; +import { SettingsComponent } from '../../../../../../main/webapp/app/account/settings/settings.component'; +import { MockAccountService } from '../../../helpers/mock-account.service'; +import { MockPrincipal } from '../../../helpers/mock-principal.service'; + + +describe('Component Tests', () => { + + describe('SettingsComponent', () => { + + let comp: SettingsComponent; + let fixture: ComponentFixture; + let mockAuth: MockAccountService; + let mockPrincipal: MockPrincipal; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [SettingsComponent], + providers: [ + { + provide: Principal, + useClass: MockPrincipal + }, + { + provide: AccountService, + useClass: MockAccountService + }, + { + provide: JhiLanguageHelper, + useValue: null + }, + ] + }).overrideComponent(SettingsComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SettingsComponent); + comp = fixture.componentInstance; + mockAuth = fixture.debugElement.injector.get(AccountService); + mockPrincipal = fixture.debugElement.injector.get(Principal); + }); + + it('should send the current identity upon save', function () { + // GIVEN + let accountValues = { + firstName: 'John', + lastName: 'Doe', + + activated: true, + email: 'john.doe@mail.com', + langKey: 'en', + login: 'john' + }; + mockPrincipal.setResponse(accountValues); + + // WHEN + comp.settingsAccount = accountValues; + comp.save(); + + // THEN + expect(mockPrincipal.identitySpy).toHaveBeenCalled(); + expect(mockAuth.saveSpy).toHaveBeenCalledWith(accountValues); + expect(comp.settingsAccount).toEqual(accountValues); + }); + + it('should notify of success upon successful save', function () { + // GIVEN + let accountValues = { + firstName: 'John', + lastName: 'Doe' + }; + mockPrincipal.setResponse(accountValues); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toBeNull(); + expect(comp.success).toBe('OK'); + }); + + it('should notify of error upon failed save', function () { + // GIVEN + mockAuth.saveSpy.and.returnValue(Observable.throw('ERROR')); + + // WHEN + comp.save(); + + // THEN + expect(comp.error).toEqual('ERROR'); + expect(comp.success).toBeNull(); + }); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts b/jhipster/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts new file mode 100644 index 0000000000..d16673de03 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/admin/audits/audits.component.spec.ts @@ -0,0 +1,82 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { DatePipe } from '@angular/common'; +import { NgbPaginationConfig} from '@ng-bootstrap/ng-bootstrap'; +import { ParseLinks } from 'ng-jhipster'; +import { BaeldungTestModule } from '../../../test.module'; +import { PaginationConfig } from '../../../../../../main/webapp/app/blocks/config/uib-pagination.config' +import { AuditsComponent } from '../../../../../../main/webapp/app/admin/audits/audits.component'; +import { AuditsService } from '../../../../../../main/webapp/app/admin/audits/audits.service'; +import { ITEMS_PER_PAGE } from '../../../../../../main/webapp/app/shared'; + + +function getDate(isToday= true){ + let date: Date = new Date(); + if (isToday) { + // Today + 1 day - needed if the current day must be included + date.setDate(date.getDate() + 1); + return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; + } + return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; +} + +describe('Component Tests', () => { + + describe('AuditsComponent', () => { + + let comp: AuditsComponent; + let fixture: ComponentFixture; + let service: AuditsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [AuditsComponent], + providers: [ + AuditsService, + NgbPaginationConfig, + ParseLinks, + PaginationConfig, + DatePipe + ] + }) + .overrideComponent(AuditsComponent, { + set: { + template: '' + } + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuditsComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(AuditsService); + }); + + describe('today function ', () => { + it('should set toDate to current date', () => { + comp.today(); + expect(comp.toDate).toBe(getDate()); + }); + }); + + describe('previousMonth function ', () => { + it('should set toDate to current date', () => { + comp.previousMonth(); + expect(comp.fromDate).toBe(getDate(false)); + }); + }); + + describe('By default, on init', () => { + it('should set all default values correctly', () => { + fixture.detectChanges(); + expect(comp.toDate).toBe(getDate()); + expect(comp.fromDate).toBe(getDate(false)); + expect(comp.itemsPerPage).toBe(ITEMS_PER_PAGE); + expect(comp.page).toBe(1); + expect(comp.reverse).toBeFalsy(); + expect(comp.orderProp).toBe('timestamp'); + }); + }); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/admin/health/health.component.spec.ts b/jhipster/src/test/javascript/spec/app/admin/health/health.component.spec.ts new file mode 100644 index 0000000000..b80c96db66 --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/admin/health/health.component.spec.ts @@ -0,0 +1,295 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { BaeldungTestModule } from '../../../test.module'; +import { JhiHealthCheckComponent } from '../../../../../../main/webapp/app/admin/health/health.component'; +import { JhiHealthService } from '../../../../../../main/webapp/app/admin/health/health.service'; + + +describe('Component Tests', () => { + + describe('JhiHealthCheckComponent', () => { + + let comp: JhiHealthCheckComponent; + let fixture: ComponentFixture; + let service: JhiHealthService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [BaeldungTestModule], + declarations: [JhiHealthCheckComponent], + providers: [ + JhiHealthService, + { + provide: NgbModal, + useValue: null + } + ] + }) + .overrideComponent(JhiHealthCheckComponent, { + set: { + template: '' + } + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JhiHealthCheckComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(JhiHealthService); + }); + + describe('baseName and subSystemName', () => { + it('should return the basename when it has no sub system', () => { + expect(comp.baseName('base')).toBe('base'); + }); + + it('should return the basename when it has sub systems', () => { + expect(comp.baseName('base.subsystem.system')).toBe('base'); + }); + + it('should return the sub system name', () => { + expect(comp.subSystemName('subsystem')).toBe(''); + }); + + it('should return the subsystem when it has multiple keys', () => { + expect(comp.subSystemName('subsystem.subsystem.system')).toBe(' - subsystem.system'); + }); + }); + + describe('transformHealthData', () => { + it('should flatten empty health data', () => { + const data = {}; + const expected = []; + expect(service.transformHealthData(data)).toEqual(expected); + }); + }); + + it('should flatten health data with no subsystems', () => { + const data = { + 'status': 'UP', + 'db': { + 'status': 'UP', + 'database': 'H2', + 'hello': '1' + }, + 'mail': { + 'status': 'UP', + 'error': 'mail.a.b.c' + } + }; + const expected = [ + { + 'name': 'db', + 'error': undefined, + 'status': 'UP', + 'details': { + 'database': 'H2', + 'hello': '1' + } + }, + { + 'name': 'mail', + 'error': 'mail.a.b.c', + 'status': 'UP' + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has no additional information', () => { + const data = { + 'status': 'UP', + 'db': { + 'status': 'UP', + 'database': 'H2', + 'hello': '1' + }, + 'mail': { + 'status': 'UP', + 'error': 'mail.a.b.c' + }, + 'system': { + 'status': 'DOWN', + 'subsystem1': { + 'status': 'UP', + 'property1': 'system.subsystem1.property1' + }, + 'subsystem2': { + 'status': 'DOWN', + 'error': 'system.subsystem1.error', + 'property2': 'system.subsystem2.property2' + } + } + }; + const expected = [ + { + 'name': 'db', + 'error': undefined, + 'status': 'UP', + 'details': { + 'database': 'H2', + 'hello': '1' + } + }, + { + 'name': 'mail', + 'error': 'mail.a.b.c', + 'status': 'UP' + }, + { + 'name': 'system.subsystem1', + 'error': undefined, + 'status': 'UP', + 'details': { + 'property1': 'system.subsystem1.property1' + } + }, + { + 'name': 'system.subsystem2', + 'error': 'system.subsystem1.error', + 'status': 'DOWN', + 'details': { + 'property2': 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional information', () => { + const data = { + 'status': 'UP', + 'db': { + 'status': 'UP', + 'database': 'H2', + 'hello': '1' + }, + 'mail': { + 'status': 'UP', + 'error': 'mail.a.b.c' + }, + 'system': { + 'status': 'DOWN', + 'property1': 'system.property1', + 'subsystem1': { + 'status': 'UP', + 'property1': 'system.subsystem1.property1' + }, + 'subsystem2': { + 'status': 'DOWN', + 'error': 'system.subsystem1.error', + 'property2': 'system.subsystem2.property2' + } + } + }; + const expected = [ + { + 'name': 'db', + 'error': undefined, + 'status': 'UP', + 'details': { + 'database': 'H2', + 'hello': '1' + } + }, + { + 'name': 'mail', + 'error': 'mail.a.b.c', + 'status': 'UP' + }, + { + 'name': 'system', + 'error': undefined, + 'status': 'DOWN', + 'details': { + 'property1': 'system.property1' + } + }, + { + 'name': 'system.subsystem1', + 'error': undefined, + 'status': 'UP', + 'details': { + 'property1': 'system.subsystem1.property1' + } + }, + { + 'name': 'system.subsystem2', + 'error': 'system.subsystem1.error', + 'status': 'DOWN', + 'details': { + 'property2': 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + + it('should flatten health data with subsystems at level 1, main system has additional error', () => { + const data = { + 'status': 'UP', + 'db': { + 'status': 'UP', + 'database': 'H2', + 'hello': '1' + }, + 'mail': { + 'status': 'UP', + 'error': 'mail.a.b.c' + }, + 'system': { + 'status': 'DOWN', + 'error': 'show me', + 'subsystem1': { + 'status': 'UP', + 'property1': 'system.subsystem1.property1' + }, + 'subsystem2': { + 'status': 'DOWN', + 'error': 'system.subsystem1.error', + 'property2': 'system.subsystem2.property2' + } + } + }; + const expected = [ + { + 'name': 'db', + 'error': undefined, + 'status': 'UP', + 'details': { + 'database': 'H2', + 'hello': '1' + } + }, + { + 'name': 'mail', + 'error': 'mail.a.b.c', + 'status': 'UP' + }, + { + 'name': 'system', + 'error': 'show me', + 'status': 'DOWN' + }, + { + 'name': 'system.subsystem1', + 'error': undefined, + 'status': 'UP', + 'details': { + 'property1': 'system.subsystem1.property1' + } + }, + { + 'name': 'system.subsystem2', + 'error': 'system.subsystem1.error', + 'status': 'DOWN', + 'details': { + 'property2': 'system.subsystem2.property2' + } + } + ]; + expect(service.transformHealthData(data)).toEqual(expected); + }); + }); +}); diff --git a/jhipster/src/test/javascript/spec/app/entities/comment/comment-detail.component.spec.ts b/jhipster/src/test/javascript/spec/app/entities/comment/comment-detail.component.spec.ts new file mode 100644 index 0000000000..b7c6b77b8c --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/entities/comment/comment-detail.component.spec.ts @@ -0,0 +1,79 @@ +import { ComponentFixture, TestBed, async, inject } from '@angular/core/testing'; +import { MockBackend } from '@angular/http/testing'; +import { Http, BaseRequestOptions } from '@angular/http'; +import { OnInit } from '@angular/core'; +import { DatePipe } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { DateUtils, DataUtils } from 'ng-jhipster'; +import { JhiLanguageService } from 'ng-jhipster'; +import { MockLanguageService } from '../../../helpers/mock-language.service'; +import { MockActivatedRoute } from '../../../helpers/mock-route.service'; +import { CommentDetailComponent } from '../../../../../../main/webapp/app/entities/comment/comment-detail.component'; +import { CommentService } from '../../../../../../main/webapp/app/entities/comment/comment.service'; +import { Comment } from '../../../../../../main/webapp/app/entities/comment/comment.model'; + +describe('Component Tests', () => { + + describe('Comment Management Detail Component', () => { + let comp: CommentDetailComponent; + let fixture: ComponentFixture; + let service: CommentService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [CommentDetailComponent], + providers: [ + MockBackend, + BaseRequestOptions, + DateUtils, + DataUtils, + DatePipe, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({id: 123}) + }, + { + provide: Http, + useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => { + return new Http(backendInstance, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + }, + { + provide: JhiLanguageService, + useClass: MockLanguageService + }, + CommentService + ] + }).overrideComponent(CommentDetailComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CommentDetailComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(CommentService); + }); + + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + spyOn(service, 'find').and.returnValue(Observable.of(new Comment(10))); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.find).toHaveBeenCalledWith(123); + expect(comp.comment).toEqual(jasmine.objectContaining({id:10})); + }); + }); + }); + +}); diff --git a/jhipster/src/test/javascript/spec/app/entities/post/post-detail.component.spec.ts b/jhipster/src/test/javascript/spec/app/entities/post/post-detail.component.spec.ts new file mode 100644 index 0000000000..3ccb9cf6ad --- /dev/null +++ b/jhipster/src/test/javascript/spec/app/entities/post/post-detail.component.spec.ts @@ -0,0 +1,79 @@ +import { ComponentFixture, TestBed, async, inject } from '@angular/core/testing'; +import { MockBackend } from '@angular/http/testing'; +import { Http, BaseRequestOptions } from '@angular/http'; +import { OnInit } from '@angular/core'; +import { DatePipe } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { DateUtils, DataUtils } from 'ng-jhipster'; +import { JhiLanguageService } from 'ng-jhipster'; +import { MockLanguageService } from '../../../helpers/mock-language.service'; +import { MockActivatedRoute } from '../../../helpers/mock-route.service'; +import { PostDetailComponent } from '../../../../../../main/webapp/app/entities/post/post-detail.component'; +import { PostService } from '../../../../../../main/webapp/app/entities/post/post.service'; +import { Post } from '../../../../../../main/webapp/app/entities/post/post.model'; + +describe('Component Tests', () => { + + describe('Post Management Detail Component', () => { + let comp: PostDetailComponent; + let fixture: ComponentFixture; + let service: PostService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PostDetailComponent], + providers: [ + MockBackend, + BaseRequestOptions, + DateUtils, + DataUtils, + DatePipe, + { + provide: ActivatedRoute, + useValue: new MockActivatedRoute({id: 123}) + }, + { + provide: Http, + useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => { + return new Http(backendInstance, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + }, + { + provide: JhiLanguageService, + useClass: MockLanguageService + }, + PostService + ] + }).overrideComponent(PostDetailComponent, { + set: { + template: '' + } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PostDetailComponent); + comp = fixture.componentInstance; + service = fixture.debugElement.injector.get(PostService); + }); + + + describe('OnInit', () => { + it('Should call load all on init', () => { + // GIVEN + + spyOn(service, 'find').and.returnValue(Observable.of(new Post(10))); + + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.find).toHaveBeenCalledWith(123); + expect(comp.post).toEqual(jasmine.objectContaining({id:10})); + }); + }); + }); + +}); diff --git a/jhipster/src/test/javascript/spec/entry.ts b/jhipster/src/test/javascript/spec/entry.ts new file mode 100644 index 0000000000..64edbafb93 --- /dev/null +++ b/jhipster/src/test/javascript/spec/entry.ts @@ -0,0 +1,19 @@ +/// +import 'core-js'; +import 'zone.js/dist/zone'; +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/proxy'; +import 'zone.js/dist/jasmine-patch'; +import 'rxjs'; +import 'intl/locale-data/jsonp/en-US.js'; +import { TestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); + +declare let require: any; +const testsContext: any = require.context('./', true, /\.spec/); +testsContext.keys().forEach(testsContext); diff --git a/jhipster/src/test/javascript/spec/helpers/mock-account.service.ts b/jhipster/src/test/javascript/spec/helpers/mock-account.service.ts new file mode 100644 index 0000000000..e21c10a370 --- /dev/null +++ b/jhipster/src/test/javascript/spec/helpers/mock-account.service.ts @@ -0,0 +1,26 @@ +import { SpyObject } from './spyobject'; +import { AccountService } from '../../../../main/webapp/app/shared/auth/account.service'; +import Spy = jasmine.Spy; + +export class MockAccountService extends SpyObject { + + getSpy: Spy; + saveSpy: Spy; + fakeResponse: any; + + constructor() { + super(AccountService); + + this.fakeResponse = null; + this.getSpy = this.spy('get').andReturn(this); + this.saveSpy = this.spy('save').andReturn(this); + } + + subscribe(callback: any) { + callback(this.fakeResponse); + } + + setResponse(json: any): void { + this.fakeResponse = json; + } +} diff --git a/jhipster/src/test/javascript/spec/helpers/mock-language.service.ts b/jhipster/src/test/javascript/spec/helpers/mock-language.service.ts new file mode 100644 index 0000000000..0c7dec92f1 --- /dev/null +++ b/jhipster/src/test/javascript/spec/helpers/mock-language.service.ts @@ -0,0 +1,26 @@ +import { SpyObject } from './spyobject'; +import { JhiLanguageService } from 'ng-jhipster'; +import Spy = jasmine.Spy; + +export class MockLanguageService extends SpyObject { + + getCurrentSpy: Spy; + fakeResponse: any; + + constructor() { + super(JhiLanguageService); + + this.fakeResponse = 'en'; + this.getCurrentSpy = this.spy('getCurrent').andReturn(Promise.resolve(this.fakeResponse)); + } + + init() {} + + changeLanguage(languageKey: string) {} + + setLocations(locations: string[]) {} + + addLocation(location: string) {} + + reload() {} +} diff --git a/jhipster/src/test/javascript/spec/helpers/mock-principal.service.ts b/jhipster/src/test/javascript/spec/helpers/mock-principal.service.ts new file mode 100644 index 0000000000..89b932b83c --- /dev/null +++ b/jhipster/src/test/javascript/spec/helpers/mock-principal.service.ts @@ -0,0 +1,20 @@ +import { SpyObject } from './spyobject'; +import { Principal } from '../../../../main/webapp/app/shared/auth/principal.service'; +import Spy = jasmine.Spy; + +export class MockPrincipal extends SpyObject { + + identitySpy: Spy; + fakeResponse: any; + + constructor() { + super(Principal); + + this.fakeResponse = {}; + this.identitySpy = this.spy('identity').andReturn(Promise.resolve(this.fakeResponse)); + } + + setResponse(json: any): void { + this.fakeResponse = json; + } +} diff --git a/jhipster/src/test/javascript/spec/helpers/mock-route.service.ts b/jhipster/src/test/javascript/spec/helpers/mock-route.service.ts new file mode 100644 index 0000000000..3ddb291721 --- /dev/null +++ b/jhipster/src/test/javascript/spec/helpers/mock-route.service.ts @@ -0,0 +1,15 @@ +import { ActivatedRoute, Params } from '@angular/router'; +import { Observable } from 'rxjs'; + +export class MockActivatedRoute extends ActivatedRoute { + + constructor(parameters?: any) { + super(); + this.queryParams = Observable.of(parameters); + this.params = Observable.of(parameters); + } +} + +export class MockRouter { + navigate = jasmine.createSpy('navigate'); +} diff --git a/jhipster/src/test/javascript/spec/helpers/spyobject.ts b/jhipster/src/test/javascript/spec/helpers/spyobject.ts new file mode 100644 index 0000000000..4db41fb8df --- /dev/null +++ b/jhipster/src/test/javascript/spec/helpers/spyobject.ts @@ -0,0 +1,69 @@ +export interface GuinessCompatibleSpy extends jasmine.Spy { + /** By chaining the spy with and.returnValue, all calls to the function will return a specific + * value. */ + andReturn(val: any): void; + /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied + * function. */ + andCallFake(fn: Function): GuinessCompatibleSpy; + /** removes all recorded calls */ + reset(); +} + +export class SpyObject { + static stub(object = null, config = null, overrides = null) { + if (!(object instanceof SpyObject)) { + overrides = config; + config = object; + object = new SpyObject(); + } + + let m = {}; + Object.keys(config).forEach((key) => m[key] = config[key]); + Object.keys(overrides).forEach((key) => m[key] = overrides[key]); + Object.keys(m).forEach((key) => { + object.spy(key).andReturn(m[key]); + }); + return object; + } + + constructor(type = null) { + if (type) { + Object.keys(type.prototype).forEach((prop) => { + let m = null; + try { + m = type.prototype[prop]; + } catch (e) { + // As we are creating spys for abstract classes, + // these classes might have getters that throw when they are accessed. + // As we are only auto creating spys for methods, this + // should not matter. + } + if (typeof m === 'function') { + this.spy(prop); + } + }); + } + } + + spy(name) { + if (!this[name]) { + this[name] = this._createGuinnessCompatibleSpy(name); + } + return this[name]; + } + + prop(name, value) { + this[name] = value; + } + + /** @internal */ + _createGuinnessCompatibleSpy(name): GuinessCompatibleSpy { + let newSpy: GuinessCompatibleSpy = < any > jasmine.createSpy(name); + newSpy.andCallFake = < any > newSpy.and.callFake; + newSpy.andReturn = < any > newSpy.and.returnValue; + newSpy.reset = < any > newSpy.calls.reset; + // revisit return null here (previously needed for rtts_assert). + newSpy.and.returnValue(null); + return newSpy; + } +} diff --git a/jhipster/src/test/javascript/spec/test.module.ts b/jhipster/src/test/javascript/spec/test.module.ts new file mode 100644 index 0000000000..65ce439cb0 --- /dev/null +++ b/jhipster/src/test/javascript/spec/test.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { MockBackend } from '@angular/http/testing'; +import { Http, BaseRequestOptions } from '@angular/http'; +import { JhiLanguageService } from 'ng-jhipster'; +import { MockLanguageService } from './helpers/mock-language.service'; + +@NgModule({ + providers: [ + MockBackend, + BaseRequestOptions, + { + provide: JhiLanguageService, + useClass: MockLanguageService + }, + { + provide: Http, + useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => { + return new Http(backendInstance, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + } + ] +}) +export class BaeldungTestModule {} diff --git a/jhipster/src/test/resources/config/application.yml b/jhipster/src/test/resources/config/application.yml new file mode 100644 index 0000000000..a7939c838c --- /dev/null +++ b/jhipster/src/test/resources/config/application.yml @@ -0,0 +1,96 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration is used for unit/integration tests. +# +# More information on profiles: https://jhipster.github.io/profiles/ +# More information on configuration properties: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + + +spring: + application: + name: baeldung + jackson: + serialization.write_dates_as_timestamps: false + cache: + type: none + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:baeldung;DB_CLOSE_DELAY=-1 + name: + username: + password: + jpa: + database-platform: io.github.jhipster.domain.util.FixedH2Dialect + database: H2 + open-in-view: false + show-sql: true + hibernate: + ddl-auto: none + naming: + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + properties: + hibernate.id.new_generator_mappings: true + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + hibernate.hbm2ddl.auto: validate + mail: + host: localhost + messages: + basename: i18n/messages + mvc: + favicon: + enabled: false + thymeleaf: + mode: XHTML + +liquibase: + contexts: test + +security: + basic: + enabled: false + +server: + port: 10344 + address: localhost + +# =================================================================== +# JHipster specific properties +# +# Full reference is available at: https://jhipster.github.io/common-application-properties/ +# =================================================================== + +jhipster: + async: + core-pool-size: 2 + max-pool-size: 50 + queue-capacity: 10000 + security: + authentication: + jwt: + secret: e1d4b69d3f953e3fa622121e882e6f459ca20ca4 + # Token is valid 24 hours + token-validity-in-seconds: 86400 + metrics: # DropWizard Metrics configuration, used by MetricsConfiguration + jmx.enabled: true + +# =================================================================== +# Application specific properties +# Add your own application properties here, see the ApplicationProperties class +# to have type-safe configuration, like in the JHipsterProperties above +# +# More documentation is available at: +# https://jhipster.github.io/common-application-properties/ +# =================================================================== + +application: diff --git a/jhipster/src/test/resources/logback-test.xml b/jhipster/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..c0acd00401 --- /dev/null +++ b/jhipster/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/jhipster/tsconfig.json b/jhipster/tsconfig.json new file mode 100644 index 0000000000..354ae048ad --- /dev/null +++ b/jhipster/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true, + "outDir": "target/www/app", + "lib": ["es6", "dom"], + "typeRoots": [ + "node_modules/@types" + ] + }, + "include": [ + "src/main/webapp/app", + "src/test/javascript" + ] +} \ No newline at end of file diff --git a/jhipster/tslint.json b/jhipster/tslint.json new file mode 100644 index 0000000000..ee6491cf69 --- /dev/null +++ b/jhipster/tslint.json @@ -0,0 +1,107 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + "static-before-instance", + "variables-before-functions" + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + + "directive-selector": [true, "attribute", "jhi", "camelCase"], + "component-selector": [true, "element", "jhi", "kebab-case"], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": false, + "component-class-suffix": true, + "directive-class-suffix": true, + "no-access-missing-member": true, + "templates-use-public": true, + "invoke-injectable": true + } +} diff --git a/jhipster/webpack/webpack.common.js b/jhipster/webpack/webpack.common.js new file mode 100644 index 0000000000..4916bb2db5 --- /dev/null +++ b/jhipster/webpack/webpack.common.js @@ -0,0 +1,117 @@ +const webpack = require('webpack'); +const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const StringReplacePlugin = require('string-replace-webpack-plugin'); +const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); +const path = require('path'); + +module.exports = function (options) { + const DATAS = { + VERSION: JSON.stringify(require("../package.json").version), + DEBUG_INFO_ENABLED: options.env === 'dev' + }; + return { + entry: { + 'polyfills': './src/main/webapp/app/polyfills', + 'global': './src/main/webapp/content/scss/global.scss', + 'main': './src/main/webapp/app/app.main' + }, + resolve: { + extensions: ['.ts', '.js'], + modules: ['node_modules'] + }, + module: { + rules: [ + { test: /bootstrap\/dist\/js\/umd\//, loader: 'imports-loader?jQuery=jquery' }, + { + test: /\.ts$/, + loaders: [ + 'angular2-template-loader', + 'awesome-typescript-loader' + ], + exclude: ['node_modules/generator-jhipster'] + }, + { + test: /\.html$/, + loader: 'raw-loader', + exclude: ['./src/main/webapp/index.html'] + }, + { + test: /\.scss$/, + loaders: ['to-string-loader', 'css-loader', 'sass-loader'], + exclude: /(vendor\.scss|global\.scss)/ + }, + { + test: /(vendor\.scss|global\.scss)/, + loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] + }, + { + test: /\.css$/, + loaders: ['to-string-loader', 'css-loader'], + exclude: /(vendor\.css|global\.css)/ + }, + { + test: /(vendor\.css|global\.css)/, + loaders: ['style-loader', 'css-loader'] + }, + { + test: /\.(jpe?g|png|gif|svg|woff|woff2|ttf|eot)$/i, + loaders: [ + 'file-loader?hash=sha512&digest=hex&name=[hash].[ext]', { + loader: 'image-webpack-loader', + query: { + gifsicle: { + interlaced: false + }, + optipng: { + optimizationLevel: 7 + } + } + } + ] + }, + { + test: /app.constants.ts$/, + loader: StringReplacePlugin.replace({ + replacements: [{ + pattern: /\/\* @toreplace (\w*?) \*\//ig, + replacement: function (match, p1, offset, string) { + return `_${p1} = ${DATAS[p1]};`; + } + }] + }) + } + ] + }, + plugins: [ + new CommonsChunkPlugin({ + names: ['manifest', 'polyfills'].reverse() + }), + new webpack.DllReferencePlugin({ + context: './', + manifest: require(path.resolve('./target/www/vendor.json')), + }), + new CopyWebpackPlugin([ + { from: './node_modules/swagger-ui/dist', to: 'swagger-ui/dist' }, + { from: './src/main/webapp/swagger-ui/', to: 'swagger-ui' }, + { from: './src/main/webapp/favicon.ico', to: 'favicon.ico' }, + { from: './src/main/webapp/robots.txt', to: 'robots.txt' }, + { from: './src/main/webapp/i18n', to: 'i18n' } + ]), + new webpack.ProvidePlugin({ + $: "jquery", + jQuery: "jquery" + }), + new HtmlWebpackPlugin({ + template: './src/main/webapp/index.html', + chunksSortMode: 'dependency', + inject: 'body' + }), + new AddAssetHtmlPlugin([ + { filepath: path.resolve('./target/www/vendor.dll.js'), includeSourcemap: false } + ]), + new StringReplacePlugin() + ] + }; +}; diff --git a/jhipster/webpack/webpack.dev.js b/jhipster/webpack/webpack.dev.js new file mode 100644 index 0000000000..f612a44b09 --- /dev/null +++ b/jhipster/webpack/webpack.dev.js @@ -0,0 +1,65 @@ +const webpack = require('webpack'); +const path = require('path'); +const commonConfig = require('./webpack.common.js'); +const writeFilePlugin = require('write-file-webpack-plugin'); +const webpackMerge = require('webpack-merge'); +const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const ENV = 'dev'; +const execSync = require('child_process').execSync; +const fs = require('fs'); +const ddlPath = './target/www/vendor.json'; + +if (!fs.existsSync(ddlPath)) { + execSync('webpack --config webpack/webpack.vendor.js'); +} + +module.exports = webpackMerge(commonConfig({ env: ENV }), { + devtool: 'inline-source-map', + devServer: { + contentBase: './target/www', + proxy: [{ + context: [ + '/api', + '/management', + '/swagger-resources', + '/v2/api-docs', + '/h2-console' + ], + target: 'http://127.0.0.1:8080', + secure: false + }] + }, + output: { + path: path.resolve('target/www'), + filename: '[name].bundle.js', + chunkFilename: '[id].chunk.js' + }, + module: { + rules: [{ + test: /\.ts$/, + loaders: [ + 'tslint-loader' + ], + exclude: ['node_modules', new RegExp('reflect-metadata\\' + path.sep + 'Reflect\\.ts')] + }] + }, + plugins: [ + new BrowserSyncPlugin({ + host: 'localhost', + port: 9000, + proxy: { + target: 'http://localhost:9060' + } + }, { + reload: false + }), + new ExtractTextPlugin('styles.css'), + new webpack.NoEmitOnErrorsPlugin(), + new webpack.NamedModulesPlugin(), + new writeFilePlugin(), + new webpack.WatchIgnorePlugin([ + path.resolve('./src/test'), + ]) + ] +}); diff --git a/jhipster/webpack/webpack.prod.js b/jhipster/webpack/webpack.prod.js new file mode 100644 index 0000000000..28f0f2152b --- /dev/null +++ b/jhipster/webpack/webpack.prod.js @@ -0,0 +1,22 @@ +const commonConfig = require('./webpack.common.js'); +const webpackMerge = require('webpack-merge'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const Visualizer = require('webpack-visualizer-plugin'); +const ENV = 'prod'; + +module.exports = webpackMerge(commonConfig({ env: ENV }), { + devtool: 'source-map', + output: { + path: './target/www', + filename: '[hash].[name].bundle.js', + chunkFilename: '[hash].[id].chunk.js' + }, + plugins: [ + new ExtractTextPlugin('[hash].styles.css'), + new Visualizer({ + // Webpack statistics in target folder + filename: '../stats.html' + }) + ] +}); diff --git a/jhipster/webpack/webpack.vendor.js b/jhipster/webpack/webpack.vendor.js new file mode 100644 index 0000000000..449024d102 --- /dev/null +++ b/jhipster/webpack/webpack.vendor.js @@ -0,0 +1,63 @@ +var webpack = require('webpack'); +module.exports = { + entry: { + 'vendor': [ + './src/main/webapp/app/vendor', + '@angular/common', + '@angular/compiler', + '@angular/core', + '@angular/forms', + '@angular/http', + '@angular/platform-browser', + '@angular/platform-browser-dynamic', + '@angular/router', + '@ng-bootstrap/ng-bootstrap', + 'angular2-cookie', + 'angular2-infinite-scroll', + 'jquery', + 'ng-jhipster', + 'ng2-webstorage', + 'rxjs' + ] + }, + resolve: { + extensions: ['.ts', '.js'], + modules: ['node_modules'] + }, + module: { + exprContextCritical: false, + rules: [ + { + test: /(vendor\.scss|global\.scss)/, + loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] + }, + { + test: /\.(jpe?g|png|gif|svg|woff|woff2|ttf|eot)$/i, + loaders: [ + 'file-loader?hash=sha512&digest=hex&name=[hash].[ext]', { + loader: 'image-webpack-loader', + query: { + gifsicle: { + interlaced: false + }, + optipng: { + optimizationLevel: 7 + } + } + } + ] + } + ] + }, + output: { + filename: '[name].dll.js', + path: './target/www', + library: '[name]' + }, + plugins: [ + new webpack.DllPlugin({ + name: '[name]', + path: './target/www/[name].json' + }) + ] +}; diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java index 786062ee57..aaa8d03585 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/ArgumentMatcherWithoutLambdaUnitTest.java @@ -13,6 +13,16 @@ import static org.mockito.Mockito.when; public class ArgumentMatcherWithoutLambdaUnitTest { + private class PeterArgumentMatcher implements ArgumentMatcher { + + @Override + public boolean matches(Person p) { + return p + .getName() + .equals("Peter"); + } + } + @InjectMocks private UnemploymentServiceImpl unemploymentService; @@ -34,16 +44,6 @@ public class ArgumentMatcherWithoutLambdaUnitTest { assertFalse(unemploymentService.personIsEntitledToUnemploymentSupport(peter)); } - private class PeterArgumentMatcher implements ArgumentMatcher { - - @Override - public boolean matches(Person p) { - return p - .getName() - .equals("Peter"); - } - } - @Before public void init() { MockitoAnnotations.initMocks(this); diff --git a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java index 9d1aa3a3c0..d5b9d6d1ce 100644 --- a/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java +++ b/mockito2/src/test/java/com/baeldung/mockito/java8/CustomAnswerWithoutLambdaUnitTest.java @@ -17,7 +17,21 @@ import static org.mockito.Mockito.when; public class CustomAnswerWithoutLambdaUnitTest { + + private class PersonAnswer implements Answer> { + @Override + public Stream answer(InvocationOnMock invocation) throws Throwable { + Person person = invocation.getArgument(0); + + if(person.getName().equals("Peter")) { + return Stream.builder().add(new JobPosition("Teacher")).build(); + } + + return Stream.empty(); + } + } + @InjectMocks private UnemploymentServiceImpl unemploymentService; @@ -37,17 +51,6 @@ public class CustomAnswerWithoutLambdaUnitTest { assertFalse(unemploymentService.searchJob(linda, "").isPresent()); } - - private class PersonAnswer implements Answer> { - - @Override - public Stream answer(InvocationOnMock invocation) throws Throwable { - Person person = invocation.getArgument(0); - - return Stream.of(new JobPosition("Teacher")) - .filter(p -> person.getName().equals("Peter")); - } - } @Before public void init() { diff --git a/pom.xml b/pom.xml index e0556a7c50..bc89f839eb 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,7 @@ javaxval jaxb jee7 + jhipster jjwt jooq jpa-storedprocedure From faea5eb5109ae8ea3606588988d46c397a56629b Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 21 Mar 2017 16:49:29 +0100 Subject: [PATCH 156/291] Refactor Javaslang samples (#1469) --- javaslang/pom.xml | 2 +- .../baeldung/javaslang/PropertyBasedTest.java | 70 ++++++++++--------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/javaslang/pom.xml b/javaslang/pom.xml index 7bb23c0daf..941aac0802 100644 --- a/javaslang/pom.xml +++ b/javaslang/pom.xml @@ -38,7 +38,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.5.1 1.8 1.8 diff --git a/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java index 3acac34550..43f3d6e6a0 100644 --- a/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java +++ b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java @@ -1,6 +1,5 @@ package com.baeldung.javaslang; - import javaslang.CheckedFunction1; import javaslang.collection.Stream; import javaslang.test.Arbitrary; @@ -8,42 +7,42 @@ import javaslang.test.CheckResult; import javaslang.test.Property; import org.junit.Test; +import java.util.function.Predicate; + +import static javaslang.API.*; + public class PropertyBasedTest { - public Stream stringsSupplier() { - return Stream.from(0).map(i -> { - boolean divByTwo = i % 2 == 0; - boolean divByFive = i % 5 == 0; + private static Predicate divisibleByTwo = i -> i % 2 == 0; + private static Predicate divisibleByFive = i -> i % 5 == 0; - if(divByFive && divByTwo){ - return "DividedByTwoAndFiveWithoutRemainder"; - }else if(divByFive){ - return "DividedByFiveWithoutRemainder"; - }else if(divByTwo){ - return "DividedByTwoWithoutRemainder"; - } - return ""; - }); + private Stream stringsSupplier() { + return Stream.from(0).map(i -> Match(i).of( + Case($(divisibleByFive.and(divisibleByTwo)), "DividedByTwoAndFiveWithoutRemainder"), + Case($(divisibleByFive), "DividedByFiveWithoutRemainder"), + Case($(divisibleByTwo), "DividedByTwoWithoutRemainder"), + Case($(), ""))); } @Test public void givenArbitrarySeq_whenCheckThatEverySecondElementIsEqualToString_thenTestPass() { //given - Arbitrary multiplesOf2 = Arbitrary.integer() - .filter(i -> i > 0) - .filter(i -> i % 2 == 0 && i % 5 != 0); + Arbitrary multiplesOf2 = Arbitrary + .integer() + .filter(i -> i > 0) + .filter(i -> i % 2 == 0 && i % 5 != 0); //when - CheckedFunction1 mustEquals = - i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder"); - + CheckedFunction1 mustEquals = i -> stringsSupplier() + .get(i) + .equals("DividedByTwoWithoutRemainder"); //then CheckResult result = Property - .def("Every second element must equal to DividedByTwoWithoutRemainder") - .forAll(multiplesOf2) - .suchThat(mustEquals) - .check(10_000, 100); + .def("Every second element must equal to DividedByTwoWithoutRemainder") + .forAll(multiplesOf2) + .suchThat(mustEquals) + .check(10_000, 100); result.assertIsSatisfied(); } @@ -51,19 +50,22 @@ public class PropertyBasedTest { @Test public void givenArbitrarySeq_whenCheckThatEveryFifthElementIsEqualToString_thenTestPass() { //given - Arbitrary multiplesOf5 = Arbitrary.integer() - .filter(i -> i > 0) - .filter(i -> i % 5 == 0 && i % 2 == 0); + Arbitrary multiplesOf5 = Arbitrary + .integer() + .filter(i -> i > 0) + .filter(i -> i % 5 == 0 && i % 2 == 0); //when - CheckedFunction1 mustEquals = i -> - stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder"); + CheckedFunction1 mustEquals = i -> stringsSupplier() + .get(i) + .endsWith("DividedByTwoAndFiveWithoutRemainder"); //then - Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder") - .forAll(multiplesOf5) - .suchThat(mustEquals) - .check(10_000, 1_000) - .assertIsSatisfied(); + Property + .def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder") + .forAll(multiplesOf5) + .suchThat(mustEquals) + .check(10_000, 1_000) + .assertIsSatisfied(); } } From eab4a5f8ca47df80b1587069fccf76ac214e41b0 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 21 Mar 2017 17:10:30 +0100 Subject: [PATCH 157/291] Move custom filter examples (#1465) * Move custom filter examples * Remove unused README entry --- spring-security-basic-auth/README.md | 1 - .../src/main/resources/webSecurityConfig.xml | 5 ---- spring-security-rest-basic-auth/README.md | 1 + .../org/baeldung}/filter/CustomFilter.java | 2 +- .../CustomWebSecurityConfigurerAdapter.java | 24 +++++++++++++------ 5 files changed, 19 insertions(+), 14 deletions(-) rename {spring-security-basic-auth/src/main/java/org/baeldung/security => spring-security-rest-basic-auth/src/main/java/org/baeldung}/filter/CustomFilter.java (92%) rename {spring-security-basic-auth/src/main/java/org/baeldung/security/filter/configuration => spring-security-rest-basic-auth/src/main/java/org/baeldung/filter}/CustomWebSecurityConfigurerAdapter.java (63%) diff --git a/spring-security-basic-auth/README.md b/spring-security-basic-auth/README.md index 8aa299f8cc..ebb404063f 100644 --- a/spring-security-basic-auth/README.md +++ b/spring-security-basic-auth/README.md @@ -7,7 +7,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com ### Relevant Article: - [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) -- [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) ### Notes diff --git a/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml b/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml index f6d15980ae..b0d483768b 100644 --- a/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml +++ b/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml @@ -11,8 +11,6 @@ - - @@ -22,7 +20,4 @@ - - - \ No newline at end of file diff --git a/spring-security-rest-basic-auth/README.md b/spring-security-rest-basic-auth/README.md index 3bd46bdd2a..328f46ed46 100644 --- a/spring-security-rest-basic-auth/README.md +++ b/spring-security-rest-basic-auth/README.md @@ -9,3 +9,4 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [RestTemplate with Basic Authentication in Spring](http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1) - [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) - [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) +- [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/security/filter/CustomFilter.java b/spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomFilter.java similarity index 92% rename from spring-security-basic-auth/src/main/java/org/baeldung/security/filter/CustomFilter.java rename to spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomFilter.java index 8d2b919cb0..01e5b0b59d 100644 --- a/spring-security-basic-auth/src/main/java/org/baeldung/security/filter/CustomFilter.java +++ b/spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomFilter.java @@ -1,4 +1,4 @@ -package org.baeldung.security.filter; +package org.baeldung.filter; import org.springframework.web.filter.GenericFilterBean; diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/security/filter/configuration/CustomWebSecurityConfigurerAdapter.java b/spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java similarity index 63% rename from spring-security-basic-auth/src/main/java/org/baeldung/security/filter/configuration/CustomWebSecurityConfigurerAdapter.java rename to spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java index d03d9cc018..2ff0e30f94 100644 --- a/spring-security-basic-auth/src/main/java/org/baeldung/security/filter/configuration/CustomWebSecurityConfigurerAdapter.java +++ b/spring-security-rest-basic-auth/src/main/java/org/baeldung/filter/CustomWebSecurityConfigurerAdapter.java @@ -1,7 +1,6 @@ -package org.baeldung.security.filter.configuration; +package org.baeldung.filter; -import org.baeldung.security.basic.MyBasicAuthenticationEntryPoint; -import org.baeldung.security.filter.CustomFilter; +import org.baeldung.security.RestAuthenticationEntryPoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -14,17 +13,28 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi @EnableWebSecurity public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { - @Autowired - private MyBasicAuthenticationEntryPoint authenticationEntryPoint; + @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user1").password("user1Pass").authorities("ROLE_USER"); + auth + .inMemoryAuthentication() + .withUser("user1") + .password("user1Pass") + .authorities("ROLE_USER"); } @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().antMatchers("/securityNone").permitAll().anyRequest().authenticated().and().httpBasic().authenticationEntryPoint(authenticationEntryPoint); + http + .authorizeRequests() + .antMatchers("/securityNone") + .permitAll() + .anyRequest() + .authenticated() + .and() + .httpBasic() + .authenticationEntryPoint(authenticationEntryPoint); http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); } From bd237b2115e045ae003d0157e85b70a87ac50d9b Mon Sep 17 00:00:00 2001 From: Alexandre Lombard Date: Tue, 21 Mar 2017 17:33:31 +0100 Subject: [PATCH 158/291] master (#1455) * Example code to return image with @ResponseBody * Example code showing how to return images using @ResponseBody * Example code showing how to return images using @ResponseBody --- .../baeldung/produceimage/Application.java | 14 +++++++ .../controller/DataProducerController.java | 38 ++++++++++++++++++ .../com/baeldung/produceimage/data.txt | 1 + .../com/baeldung/produceimage/image.jpg | Bin 0 -> 6170 bytes 4 files changed, 53 insertions(+) create mode 100644 spring-rest/src/main/java/com/baeldung/produceimage/Application.java create mode 100644 spring-rest/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java create mode 100644 spring-rest/src/main/resources/com/baeldung/produceimage/data.txt create mode 100644 spring-rest/src/main/resources/com/baeldung/produceimage/image.jpg diff --git a/spring-rest/src/main/java/com/baeldung/produceimage/Application.java b/spring-rest/src/main/java/com/baeldung/produceimage/Application.java new file mode 100644 index 0000000000..179671d094 --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/produceimage/Application.java @@ -0,0 +1,14 @@ +package com.baeldung.produceimage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.PropertySource; + +@EnableAutoConfiguration +@ComponentScan("com.baeldung.produceimage") +public class Application { + public static void main(final String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-rest/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java b/spring-rest/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java new file mode 100644 index 0000000000..6f34bdb9ae --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/produceimage/controller/DataProducerController.java @@ -0,0 +1,38 @@ +package com.baeldung.produceimage.controller; + +import org.apache.commons.io.IOUtils; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.io.IOException; +import java.io.InputStream; + +@Controller +public class DataProducerController { + + @GetMapping("/get-text") + public @ResponseBody String getText() { + return "Hello world"; + } + + @GetMapping(value = "/get-image") + public @ResponseBody byte[] getImage() throws IOException { + final InputStream in = getClass().getResourceAsStream("/com/baeldung/produceimage/image.jpg"); + return IOUtils.toByteArray(in); + } + + @GetMapping(value = "/get-image-with-media-type", produces = MediaType.IMAGE_JPEG_VALUE) + public @ResponseBody byte[] getImageWithMediaType() throws IOException { + final InputStream in = getClass().getResourceAsStream("/com/baeldung/produceimage/image.jpg"); + return IOUtils.toByteArray(in); + } + + @GetMapping(value = "/get-file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public @ResponseBody byte[] getFile() throws IOException { + final InputStream in = getClass().getResourceAsStream("/com/baeldung/produceimage/data.txt"); + return IOUtils.toByteArray(in); + } + +} diff --git a/spring-rest/src/main/resources/com/baeldung/produceimage/data.txt b/spring-rest/src/main/resources/com/baeldung/produceimage/data.txt new file mode 100644 index 0000000000..3cd18170c0 --- /dev/null +++ b/spring-rest/src/main/resources/com/baeldung/produceimage/data.txt @@ -0,0 +1 @@ +This is a sample file containing text data \ No newline at end of file diff --git a/spring-rest/src/main/resources/com/baeldung/produceimage/image.jpg b/spring-rest/src/main/resources/com/baeldung/produceimage/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0262656a33a02978a6c4a4754856801a839fd597 GIT binary patch literal 6170 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 literal 0 HcmV?d00001 From d66703b5d9340c67a94ec59e5e66686cb0058691 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Tue, 21 Mar 2017 17:46:06 -0500 Subject: [PATCH 159/291] BAEL-680: rename test methods (#1470) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods --- .../java8/comparator/Java8ComparatorTest.java | 60 ++++--------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java index 5c338101d8..57e3898274 100644 --- a/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java +++ b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java @@ -60,7 +60,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingComparing_thenCheckingSort() { + public void whenComparing_thenSortedByName() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Arrays.sort(employees, employeeNameComparator); // System.out.println(Arrays.toString(employees)); @@ -68,7 +68,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingComparingWithComparator_thenCheckingSort() { + public void whenComparingWithComparator_thenSortedByNameDesc() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName, (s1, s2) -> { return s2.compareTo(s1); }); @@ -78,7 +78,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingComparingInt_thenCheckingSort() { + public void whenComparingInt_thenSortedByAge() { Comparator employeeAgeComparator = Comparator.comparingInt(Employee::getAge); Arrays.sort(employees, employeeAgeComparator); // System.out.println(Arrays.toString(employees)); @@ -86,7 +86,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingComparingLong_thenCheckingSort() { + public void whenComparingLong_thenSortedByMobile() { Comparator employeeMobileComparator = Comparator.comparingLong(Employee::getMobile); Arrays.sort(employees, employeeMobileComparator); // System.out.println(Arrays.toString(employees)); @@ -94,7 +94,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingComparingDouble_thenCheckingSort() { + public void whenComparingDouble_thenSortedBySalary() { Comparator employeeSalaryComparator = Comparator.comparingDouble(Employee::getSalary); Arrays.sort(employees, employeeSalaryComparator); // System.out.println(Arrays.toString(employees)); @@ -102,7 +102,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingNaturalOrder_thenCheckingSort() { + public void whenNaturalOrder_thenSortedByName() { Comparator employeeNameComparator = Comparator. naturalOrder(); Arrays.sort(employees, employeeNameComparator); // System.out.println(Arrays.toString(employees)); @@ -110,7 +110,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingReverseOrder_thenCheckingSort() { + public void whenReverseOrder_thenSortedByNameDesc() { Comparator employeeNameComparator = Comparator. reverseOrder(); Arrays.sort(employees, employeeNameComparator); // System.out.println(Arrays.toString(employees)); @@ -118,7 +118,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingNullFirst_thenCheckingSort() { + public void whenNullsFirst_thenSortedByNameWithNullsFirst() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Comparator employeeNameComparator_nullFirst = Comparator.nullsFirst(employeeNameComparator); Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullFirst); @@ -127,7 +127,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingNullLast_thenCheckingSort() { + public void whenNullsLast_thenSortedByNameWithNullsLast() { Comparator employeeNameComparator = Comparator.comparing(Employee::getName); Comparator employeeNameComparator_nullLast = Comparator.nullsLast(employeeNameComparator); Arrays.sort(employeesArrayWithNulls, employeeNameComparator_nullLast); @@ -136,7 +136,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingThenComparing_thenCheckingSort() { + public void whenThenComparing_thenSortedByAgeName() { Comparator employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge).thenComparing(Employee::getName); Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator); @@ -145,7 +145,7 @@ public class Java8ComparatorTest { } @Test - public void givenEmployeeArray_whenUsingThenComparingInt_thenCheckingSort() { + public void whenThenComparing_thenSortedByNameAge() { Comparator employee_Name_Age_Comparator = Comparator.comparing(Employee::getName).thenComparingInt(Employee::getAge); Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator); @@ -153,40 +153,4 @@ public class Java8ComparatorTest { assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByNameAge)); } - @Before - public void printData() { -// System.out.println("employees"); -// System.out.println(Arrays.toString(employees)); - // -// System.out.println("employeesArrayWithNulls"); -// System.out.println(Arrays.toString(employeesArrayWithNulls)); - // - // System.out.println("sortedEmployeesByName"); - // System.out.println(Arrays.toString(sortedEmployeesByName)); - // - // System.out.println("sortedEmployeesByNameDesc"); - // System.out.println(Arrays.toString(sortedEmployeesByNameDesc)); - // - // System.out.println("sortedEmployeesByAge"); - // System.out.println(Arrays.toString(sortedEmployeesByAge)); - // - // System.out.println("sortedEmployeesByMobile"); - // System.out.println(Arrays.toString(sortedEmployeesByMobile)); - // - // System.out.println("sortedEmployeesBySalary"); - // System.out.println(Arrays.toString(sortedEmployeesBySalary)); - // - // System.out.println("sortedEmployeesArray_WithNullsFirst"); - // System.out.println(Arrays.toString(sortedEmployeesArray_WithNullsFirst)); - // - // System.out.println("sortedEmployeesArray_WithNullsLast"); - // System.out.println(Arrays.toString(sortedEmployeesArray_WithNullsLast)); - // - // System.out.println("sortedEmployeesByNameAge"); - // System.out.println(Arrays.toString(sortedEmployeesByNameAge)); - // -// System.out.println("someMoreEmployees"); -// System.out.println(Arrays.toString(someMoreEmployees)); - // - } -} +} \ No newline at end of file From e71358a9dec1baab03c32323940facc5645f73c6 Mon Sep 17 00:00:00 2001 From: Justin Wilson Date: Wed, 22 Mar 2017 12:47:23 +0000 Subject: [PATCH 160/291] BAEL-503: initial commit of a simple Spring AMQL example application (#1467) --- pom.xml | 1 + spring-amqp-simple/pom.xml | 46 ++++++++++++++++++ .../springamqpsimple/MessageConsumer.java | 15 ++++++ .../springamqpsimple/MessageController.java | 26 ++++++++++ .../springamqpsimple/MessageProducer.java | 20 ++++++++ .../SpringAmqpApplication.java | 12 +++++ .../springamqpsimple/SpringAmqpConfig.java | 48 +++++++++++++++++++ .../src/main/resources/application.yaml | 4 ++ .../MessageControllerTest.java | 45 +++++++++++++++++ 9 files changed, 217 insertions(+) create mode 100644 spring-amqp-simple/pom.xml create mode 100644 spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageConsumer.java create mode 100644 spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageController.java create mode 100644 spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageProducer.java create mode 100644 spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpApplication.java create mode 100644 spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpConfig.java create mode 100644 spring-amqp-simple/src/main/resources/application.yaml create mode 100644 spring-amqp-simple/src/test/java/com/baeldung/springamqpsimple/MessageControllerTest.java diff --git a/pom.xml b/pom.xml index 1a1108cb99..15e0e3322e 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,7 @@ spring-akka spring-amqp spring-all + spring-amqp-simple spring-apache-camel spring-batch spring-boot diff --git a/spring-amqp-simple/pom.xml b/spring-amqp-simple/pom.xml new file mode 100644 index 0000000000..38738d875f --- /dev/null +++ b/spring-amqp-simple/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + com.baeldung + spring-amqp-simple + 1.0.0-SNAPSHOT + Spring AMQP Simple App + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-amqp + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageConsumer.java b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageConsumer.java new file mode 100644 index 0000000000..b757dfebe8 --- /dev/null +++ b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageConsumer.java @@ -0,0 +1,15 @@ +package com.baeldung.springamqpsimple; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +@Component +public class MessageConsumer { + + private static final Logger logger = LogManager.getLogger(MessageConsumer.class); + + public void receiveMessage(String message) { + logger.info("Received Message: " + message); + } +} diff --git a/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageController.java b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageController.java new file mode 100644 index 0000000000..deef22c4d6 --- /dev/null +++ b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageController.java @@ -0,0 +1,26 @@ +package com.baeldung.springamqpsimple; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; + +@Controller +public class MessageController { + + private final MessageProducer messageProducer; + + @Autowired + public MessageController(MessageProducer messageProducer) { + this.messageProducer = messageProducer; + } + + @RequestMapping(value="/messages", method= RequestMethod.POST) + @ResponseStatus(value= HttpStatus.CREATED) + public void sendMessage(@RequestBody String message) { + messageProducer.sendMessage(message); + } +} diff --git a/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageProducer.java b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageProducer.java new file mode 100644 index 0000000000..225f37bdd0 --- /dev/null +++ b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/MessageProducer.java @@ -0,0 +1,20 @@ +package com.baeldung.springamqpsimple; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class MessageProducer { + + private final RabbitTemplate rabbitTemplate; + + @Autowired + public MessageProducer(RabbitTemplate rabbitTemplate) { + this.rabbitTemplate = rabbitTemplate; + } + + public void sendMessage(String message) { + rabbitTemplate.convertAndSend(SpringAmqpConfig.queueName, message); + } +} diff --git a/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpApplication.java b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpApplication.java new file mode 100644 index 0000000000..b84a49a230 --- /dev/null +++ b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.springamqpsimple; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringAmqpApplication { + + public static void main(String[] args) throws InterruptedException { + SpringApplication.run(SpringAmqpApplication.class, args); + } +} diff --git a/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpConfig.java b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpConfig.java new file mode 100644 index 0000000000..78d79dd47a --- /dev/null +++ b/spring-amqp-simple/src/main/java/com/baeldung/springamqpsimple/SpringAmqpConfig.java @@ -0,0 +1,48 @@ +package com.baeldung.springamqpsimple; + +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("!test") +public class SpringAmqpConfig { + + public final static String queueName = "com.baeldung.spring-amqp-simple.queue"; + public final static String exchangeName = "com.baeldung.spring-amqp-simple.exchange"; + + @Bean + Queue queue() { + return new Queue(queueName, false); + } + + @Bean + Exchange exchange() { + return new DirectExchange(exchangeName); + } + + @Bean + Binding binding(Queue queue, DirectExchange exchange) { + return BindingBuilder.bind(queue).to(exchange).with(queueName); + } + + @Bean + SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, + MessageListenerAdapter listenerAdapter) { + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + container.setQueueNames(queueName); + container.setMessageListener(listenerAdapter); + return container; + } + + @Bean + MessageListenerAdapter listenerAdapter(MessageConsumer messageReceiver) { + return new MessageListenerAdapter(messageReceiver, "receiveMessage"); + } + +} diff --git a/spring-amqp-simple/src/main/resources/application.yaml b/spring-amqp-simple/src/main/resources/application.yaml new file mode 100644 index 0000000000..4aca1bb783 --- /dev/null +++ b/spring-amqp-simple/src/main/resources/application.yaml @@ -0,0 +1,4 @@ +spring: + rabbitmq: + username: baeldung + password: baeldung \ No newline at end of file diff --git a/spring-amqp-simple/src/test/java/com/baeldung/springamqpsimple/MessageControllerTest.java b/spring-amqp-simple/src/test/java/com/baeldung/springamqpsimple/MessageControllerTest.java new file mode 100644 index 0000000000..c62c86290a --- /dev/null +++ b/spring-amqp-simple/src/test/java/com/baeldung/springamqpsimple/MessageControllerTest.java @@ -0,0 +1,45 @@ +package com.baeldung.springamqpsimple; + + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; + +@RunWith(SpringRunner.class) +@ActiveProfiles("test") +@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT) +public class MessageControllerTest { + + @Autowired + private TestRestTemplate restTemplate; + + @MockBean + private RabbitTemplate rabbitTemplate; + + @Test + public void whenPostingMessage_thenMessageIsCreated() { + final String message = "Hello World!"; + ResponseEntity responseEntity = restTemplate.postForEntity("/messages", message, Void.class); + + assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); + } + + @Test + public void whenPostingMessage_thenMessageIsSentToBroker() { + final String message = "Hello World!"; + restTemplate.postForEntity("/messages", message, Void.class); + + verify(rabbitTemplate).convertAndSend(SpringAmqpConfig.queueName, message); + } +} \ No newline at end of file From a055ab5f81698fdf2330edd9d0a51371d4e18c4f Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 22 Mar 2017 19:29:59 -0500 Subject: [PATCH 161/291] BAEL-714: Updated README.md (#1475) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md --- spring-mvc-forms/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-mvc-forms/README.md b/spring-mvc-forms/README.md index 745851a102..86abd7e4c1 100644 --- a/spring-mvc-forms/README.md +++ b/spring-mvc-forms/README.md @@ -3,3 +3,4 @@ ### Relevant Articles - [MaxUploadSizeExceededException in Spring](http://www.baeldung.com/spring-maxuploadsizeexceeded) - [Getting Started with Forms in Spring MVC](http://www.baeldung.com/spring-mvc-form-tutorial) +- [Form Validation with AngularJS and Spring MVC](http://www.baeldung.com/validation-angularjs-spring-mvc) From 6def7456405f69e21485f0bec25c2c018e870301 Mon Sep 17 00:00:00 2001 From: shankarps Date: Wed, 22 Mar 2017 18:13:26 -0700 Subject: [PATCH 162/291] BAEL-679. Java 9 Reactive Streams. Second draft. --- .../reactive/BaeldungBatchSubscriberImpl.java | 84 +++++++++++++++ .../reactive/BaeldungSubscriberImpl.java | 55 ++++++++++ .../BaeldungBatchSubscriberImplTest.java | 75 +++++++++++++ .../reactive/BaeldungSubscriberImplTest.java | 100 ++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 100644 core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java create mode 100644 core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungSubscriberImpl.java create mode 100644 core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImplTest.java create mode 100644 core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungSubscriberImplTest.java diff --git a/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java new file mode 100644 index 0000000000..4c65cb35b6 --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java @@ -0,0 +1,84 @@ +package com.baeldung.java9.reactive; + +import java.util.ArrayList; +import java.util.concurrent.Flow.Subscriber; +import java.util.concurrent.Flow.Subscription; + +public class BaeldungBatchSubscriberImpl implements Subscriber { + private Subscription subscription; + private boolean completed = false; + private int counter; + private ArrayList buffer; + public static final int BUFFER_SIZE = 5; + + public BaeldungBatchSubscriberImpl() { + buffer = new ArrayList(); + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + public int getCounter() { + return counter; + } + + public void setCounter(int counter) { + this.counter = counter; + } + + @Override + public void onSubscribe(Subscription subscription) { + this.subscription = subscription; + subscription.request(BUFFER_SIZE); + } + + @Override + public void onNext(String item) { + buffer.add(item); + // if buffer is full, process the items. + if (buffer.size() >= BUFFER_SIZE) { + processBuffer(); + subscription.request(BUFFER_SIZE); + } else if(buffer.size() == 0) { + // If buffer empty, request more items. + subscription.request(BUFFER_SIZE); + } + } + + private void processBuffer() { + if (buffer.isEmpty()) + return; + // Process all items in the buffer. Here, we just print it and sleep for 1 second. + System.out.print("Processed items: "); + buffer.stream() + .forEach(item -> { + System.out.print(" " + item); + }); + System.out.println(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + counter = counter + buffer.size(); + buffer.clear(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + } + + @Override + public void onComplete() { + completed = true; + // process any remaining items in buffer before + processBuffer(); + subscription.cancel(); + } +} diff --git a/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungSubscriberImpl.java b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungSubscriberImpl.java new file mode 100644 index 0000000000..bacd777255 --- /dev/null +++ b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungSubscriberImpl.java @@ -0,0 +1,55 @@ +package com.baeldung.java9.reactive; + +import java.util.concurrent.Flow.Subscriber; +import java.util.concurrent.Flow.Subscription; + +public class BaeldungSubscriberImpl implements Subscriber { + private Subscription subscription; + private boolean completed = false; + private int counter; + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + public int getCounter() { + return counter; + } + + public void setCounter(int counter) { + this.counter = counter; + } + + @Override + public void onSubscribe(Subscription subscription) { + this.subscription = subscription; + subscription.request(1); + } + + @Override + public void onNext(String item) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + counter++; + System.out.println("Processed item : " + item); + subscription.request(1); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + } + + @Override + public void onComplete() { + completed = true; + subscription.cancel(); + } +} diff --git a/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImplTest.java b/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImplTest.java new file mode 100644 index 0000000000..388d3efdd8 --- /dev/null +++ b/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImplTest.java @@ -0,0 +1,75 @@ +package com.baeldung.java9.reactive; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Stopwatch; + +public class BaeldungBatchSubscriberImplTest { + + private static final int ITEM_SIZE = 10; + private SubmissionPublisher publisher; + private BaeldungBatchSubscriberImpl subscriber; + + @Before + public void initialize() { + this.publisher = new SubmissionPublisher(ForkJoinPool.commonPool(), 6); + this.subscriber = new BaeldungBatchSubscriberImpl(); + publisher.subscribe(subscriber); + } + + @Rule + public Stopwatch stopwatch = new Stopwatch() { + + }; + + @Test + public void testReactiveStreamCount() { + IntStream.range(0, ITEM_SIZE) + .forEach(item -> publisher.submit(item + "")); + publisher.close(); + + do { + // wait for subscribers to complete all processing. + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (!subscriber.isCompleted()); + + int count = subscriber.getCounter(); + + assertEquals(ITEM_SIZE, count); + } + + @Test + public void testReactiveStreamTime() { + IntStream.range(0, ITEM_SIZE) + .forEach(item -> publisher.submit(item + "")); + publisher.close(); + + do { + // wait for subscribers to complete all processing. + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (!subscriber.isCompleted()); + + // The runtime in seconds should be equal to the number of items in each batch. + assertTrue(stopwatch.runtime(TimeUnit.SECONDS) >= (ITEM_SIZE / subscriber.BUFFER_SIZE)); + } + +} diff --git a/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungSubscriberImplTest.java b/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungSubscriberImplTest.java new file mode 100644 index 0000000000..5638c0a431 --- /dev/null +++ b/core-java-9/src/test/java/com/baeldung/java9/reactive/BaeldungSubscriberImplTest.java @@ -0,0 +1,100 @@ +package com.baeldung.java9.reactive; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.SubmissionPublisher; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Stopwatch; + +public class BaeldungSubscriberImplTest { + + private static final int ITEM_SIZE = 10; + private SubmissionPublisher publisher; + private BaeldungSubscriberImpl subscriber; + + @Before + public void initialize() { + // create Publisher with max buffer capacity 3. + this.publisher = new SubmissionPublisher(ForkJoinPool.commonPool(), 3); + this.subscriber = new BaeldungSubscriberImpl(); + publisher.subscribe(subscriber); + } + + @Rule + public Stopwatch stopwatch = new Stopwatch() { + + }; + + @Test + public void testReactiveStreamCount() { + IntStream.range(0, ITEM_SIZE) + .forEach(item -> publisher.submit(item + "")); + publisher.close(); + + do { + // wait for subscribers to complete all processing. + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (!subscriber.isCompleted()); + + int count = subscriber.getCounter(); + + assertEquals(ITEM_SIZE, count); + } + + @Test + public void testReactiveStreamTime() { + IntStream.range(0, ITEM_SIZE) + .forEach(item -> publisher.submit(item + "")); + publisher.close(); + + do { + // wait for subscribers to complete all processing. + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (!subscriber.isCompleted()); + + // The runtime in seconds should be equal to the number of items. + assertTrue(stopwatch.runtime(TimeUnit.SECONDS) >= ITEM_SIZE); + } + + @Test + public void testReactiveStreamOffer() { + IntStream.range(0, ITEM_SIZE) + .forEach(item -> publisher.offer(item + "", (subscriber, string) -> { + // Returning false means this item will be dropped (no retry), if blocked. + return false; + })); + publisher.close(); + + do { + // wait for subscribers to complete all processing. + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } while (!subscriber.isCompleted()); + + int count = subscriber.getCounter(); + // Because 10 items were offered and the buffer capacity was 3, few items will not be processed. + assertTrue(ITEM_SIZE > count); + } + +} From b01c2c5a949339419e54ebcd7635ccdc12f311ef Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Thu, 23 Mar 2017 13:46:32 +0100 Subject: [PATCH 163/291] Bael 361 jackson streaming (#1459) * BAEL-361 tests for Streaming API * BAEL-361 do not use deprecated API * BAEL-361 return to not read whole json document, only needed field --- .../streaming/JacksonStreamingAPITest.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 jackson/src/test/java/com/baeldung/jackson/streaming/JacksonStreamingAPITest.java diff --git a/jackson/src/test/java/com/baeldung/jackson/streaming/JacksonStreamingAPITest.java b/jackson/src/test/java/com/baeldung/jackson/streaming/JacksonStreamingAPITest.java new file mode 100644 index 0000000000..6f61793315 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/streaming/JacksonStreamingAPITest.java @@ -0,0 +1,119 @@ +package com.baeldung.jackson.streaming; + + +import com.fasterxml.jackson.core.*; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.TestCase.assertEquals; + +public class JacksonStreamingAPITest { + + @Test + public void givenJsonGenerator_whenAppendJsonToIt_thenGenerateJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + + //when + jGenerator.writeStartObject(); + jGenerator.writeStringField("name", "Tom"); + jGenerator.writeNumberField("age", 25); + jGenerator.writeFieldName("address"); + jGenerator.writeStartArray(); + jGenerator.writeString("Poland"); + jGenerator.writeString("5th avenue"); + jGenerator.writeEndArray(); + jGenerator.writeEndObject(); + jGenerator.close(); + + //then + String json = new String(stream.toByteArray(), "UTF-8"); + assertEquals(json, "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}"); + } + + @Test + public void givenJson_whenReadItUsingStreamAPI_thenShouldCreateProperJsonObject() throws IOException { + //given + String json = "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}"; + JsonFactory jfactory = new JsonFactory(); + JsonParser jParser = jfactory.createParser(json); + + String parsedName = null; + Integer parsedAge = null; + List addresses = new LinkedList<>(); + + //when + while (jParser.nextToken() != JsonToken.END_OBJECT) { + + String fieldname = jParser.getCurrentName(); + if ("name".equals(fieldname)) { + jParser.nextToken(); + parsedName = jParser.getText(); + + } + + if ("age".equals(fieldname)) { + jParser.nextToken(); + parsedAge = jParser.getIntValue(); + + } + + if ("address".equals(fieldname)) { + jParser.nextToken(); + + while (jParser.nextToken() != JsonToken.END_ARRAY) { + addresses.add(jParser.getText()); + } + } + + } + jParser.close(); + + //then + assertEquals(parsedName, "Tom"); + assertEquals(parsedAge, (Integer) 25); + assertEquals(addresses, Arrays.asList("Poland", "5th avenue")); + + } + + @Test + public void givenJson_whenWantToExtractPartOfIt_thenShouldExtractOnlyNeededFieldWithoutGoingThroughWholeJSON() throws IOException { + //given + String json = "{\"name\":\"Tom\",\"age\":25,\"address\":[\"Poland\",\"5th avenue\"]}"; + JsonFactory jfactory = new JsonFactory(); + JsonParser jParser = jfactory.createParser(json); + + String parsedName = null; + Integer parsedAge = null; + List addresses = new LinkedList<>(); + + //when + while (jParser.nextToken() != JsonToken.END_OBJECT) { + + String fieldname = jParser.getCurrentName(); + + if ("age".equals(fieldname)) { + jParser.nextToken(); + parsedAge = jParser.getIntValue(); + return; + } + + } + jParser.close(); + + //then + assertNull(parsedName); + assertEquals(parsedAge, (Integer) 25); + assertTrue(addresses.isEmpty()); + + } +} From e884e3f92455a9dd9f620d57952e8826d54f4639 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Fri, 24 Mar 2017 02:20:30 +0530 Subject: [PATCH 164/291] update spring-kafka project with support for multiple partitions and JSON serializer (#1472) --- spring-kafka/README.md | 26 ++++- spring-kafka/pom.xml | 12 +- .../com/baeldung/spring/kafka/Greeting.java | 37 ++++++ .../spring/kafka/KafkaApplication.java | 105 +++++++++++++++++- .../spring/kafka/KafkaConsumerConfig.java | 41 ++++++- .../spring/kafka/KafkaProducerConfig.java | 20 +++- .../src/main/resources/application.properties | 3 + 7 files changed, 228 insertions(+), 16 deletions(-) create mode 100644 spring-kafka/src/main/java/com/baeldung/spring/kafka/Greeting.java diff --git a/spring-kafka/README.md b/spring-kafka/README.md index 2731eca042..c8f01cc28b 100644 --- a/spring-kafka/README.md +++ b/spring-kafka/README.md @@ -2,8 +2,28 @@ This is a simple Spring Boot app to demonstrate sending and receiving of messages in Kafka using spring-kafka. -As Kafka topics are not created automatically by default, this application requires that a topic named 'baeldung' is created manually. +As Kafka topics are not created automatically by default, this application requires that you create the following topics manually. -`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic baeldung` +`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic baeldung`
+`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 5 --topic partitioned`
+`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic filtered`
+`$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic greeting`
-Two listeners with group Ids **foo** and **bar** are configured. When run successfully, the *Hello World!* message will be received by both the listeners and logged on console. +When the application runs successfully, following output is logged on to console (along with spring logs): + +#### Message received from the 'baeldung' topic by the basic listeners with groups foo and bar +>Received Messasge in group 'foo': Hello, World!
+Received Messasge in group 'bar': Hello, World! + +#### Message received from the 'baeldung' topic, with the partition info +>Received Messasge: Hello, World! from partition: 0 + +#### Message received from the 'partitioned' topic, only from specific partitions +>Received Message: Hello To Partioned Topic! from partition: 0
+Received Message: Hello To Partioned Topic! from partition: 3 + +#### Message received from the 'filtered' topic after filtering +>Recieved Message in filtered listener: Hello Baeldung! + +#### Message (Serialized Java Object) received from the 'greeting' topic +>Recieved greeting message: Greetings, World!! \ No newline at end of file diff --git a/spring-kafka/pom.xml b/spring-kafka/pom.xml index 73eaf3acff..11810a17dd 100644 --- a/spring-kafka/pom.xml +++ b/spring-kafka/pom.xml @@ -12,6 +12,7 @@ 1.8 1.1.3.RELEASE + 2.6.7 @@ -21,17 +22,22 @@ - + org.springframework.boot spring-boot-starter - + org.springframework.kafka spring-kafka - + + + com.fasterxml.jackson.core + jackson-databind + + diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/Greeting.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/Greeting.java new file mode 100644 index 0000000000..b4633e802a --- /dev/null +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/Greeting.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.kafka; + +public class Greeting { + + private String msg; + private String name; + + public Greeting() { + + } + + public Greeting(String msg, String name) { + this.msg = msg; + this.name = name; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return msg + ", " + name + "!"; + } +} diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java index 252054a9f1..50978d5ea9 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaApplication.java @@ -10,21 +10,61 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.annotation.TopicPartition; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Payload; @SpringBootApplication public class KafkaApplication { public static void main(String[] args) throws Exception { + ConfigurableApplicationContext context = SpringApplication.run(KafkaApplication.class, args); + MessageProducer producer = context.getBean(MessageProducer.class); - producer.sendMessage("Hello, World!"); - MessageListener listener = context.getBean(MessageListener.class); - listener.latch.await(20, TimeUnit.SECONDS); - Thread.sleep(60000); - context.close(); + /* + * Sending a Hello World message to topic 'baeldung'. + * Must be recieved by both listeners with group foo + * and bar with containerFactory fooKafkaListenerContainerFactory + * and barKafkaListenerContainerFactory respectively. + * It will also be recieved by the listener with + * headersKafkaListenerContainerFactory as container factory + */ + producer.sendMessage("Hello, World!"); + listener.latch.await(10, TimeUnit.SECONDS); + /* + * Sending message to a topic with 5 partition, + * each message to a different partition. But as per + * listener configuration, only the messages from + * partition 0 and 3 will be consumed. + */ + for (int i = 0; i < 5; i++) { + producer.sendMessageToPartion("Hello To Partioned Topic!", i); + } + listener.partitionLatch.await(10, TimeUnit.SECONDS); + + /* + * Sending message to 'filtered' topic. As per listener + * configuration, all messages with char sequence + * 'World' will be discarded. + */ + producer.sendMessageToFiltered("Hello Baeldung!"); + producer.sendMessageToFiltered("Hello World!"); + listener.filterLatch.await(10, TimeUnit.SECONDS); + + /* + * Sending message to 'greeting' topic. This will send + * and recieved a java object with the help of + * greetingKafkaListenerContainerFactory. + */ + producer.sendGreetingMessage(new Greeting("Greetings", "World!")); + listener.greetingLatch.await(10, TimeUnit.SECONDS); + + context.close(); } @Bean @@ -42,18 +82,47 @@ public class KafkaApplication { @Autowired private KafkaTemplate kafkaTemplate; + @Autowired + private KafkaTemplate greetingKafkaTemplate; + @Value(value = "${message.topic.name}") private String topicName; + @Value(value = "${partitioned.topic.name}") + private String partionedTopicName; + + @Value(value = "${filtered.topic.name}") + private String filteredTopicName; + + @Value(value = "${greeting.topic.name}") + private String greetingTopicName; + public void sendMessage(String message) { kafkaTemplate.send(topicName, message); } + public void sendMessageToPartion(String message, int partition) { + kafkaTemplate.send(partionedTopicName, partition, message); + } + + public void sendMessageToFiltered(String message) { + kafkaTemplate.send(filteredTopicName, message); + } + + public void sendGreetingMessage(Greeting greeting) { + greetingKafkaTemplate.send(greetingTopicName, greeting); + } } public static class MessageListener { - private CountDownLatch latch = new CountDownLatch(2); + private CountDownLatch latch = new CountDownLatch(3); + + private CountDownLatch partitionLatch = new CountDownLatch(2); + + private CountDownLatch filterLatch = new CountDownLatch(2); + + private CountDownLatch greetingLatch = new CountDownLatch(1); @KafkaListener(topics = "${message.topic.name}", group = "foo", containerFactory = "fooKafkaListenerContainerFactory") public void listenGroupFoo(String message) { @@ -67,6 +136,30 @@ public class KafkaApplication { latch.countDown(); } + @KafkaListener(topics = "${message.topic.name}", containerFactory = "headersKafkaListenerContainerFactory") + public void listenWithHeaders(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + System.out.println("Received Messasge: " + message + " from partition: " + partition); + latch.countDown(); + } + + @KafkaListener(topicPartitions = @TopicPartition(topic = "${partitioned.topic.name}", partitions = { "0", "3" })) + public void listenToParition(@Payload String message, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + System.out.println("Received Message: " + message + " from partition: " + partition); + this.partitionLatch.countDown(); + } + + @KafkaListener(topics = "${filtered.topic.name}", containerFactory = "filterKafkaListenerContainerFactory") + public void listenWithFilter(String message) { + System.out.println("Recieved Message in filtered listener: " + message); + this.filterLatch.countDown(); + } + + @KafkaListener(topics = "${greeting.topic.name}", containerFactory = "greetingKafkaListenerContainerFactory") + public void greetingListener(Greeting greeting) { + System.out.println("Recieved greeting message: " + greeting); + this.greetingLatch.countDown(); + } + } } diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java index f9edda2435..9353e63ff6 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java @@ -12,6 +12,7 @@ import org.springframework.kafka.annotation.EnableKafka; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; @EnableKafka @Configuration @@ -35,11 +36,49 @@ public class KafkaConsumerConfig { factory.setConsumerFactory(consumerFactory("foo")); return factory; } - + @Bean public ConcurrentKafkaListenerContainerFactory barKafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory("bar")); return factory; } + + @Bean + public ConcurrentKafkaListenerContainerFactory headersKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory("headers")); + return factory; + } + + @Bean + public ConcurrentKafkaListenerContainerFactory partitionsKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory("partitions")); + return factory; + } + + @Bean + public ConcurrentKafkaListenerContainerFactory filterKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory("filter")); + factory.setRecordFilterStrategy(record -> record.value() + .contains("World")); + return factory; + } + + public ConsumerFactory greetingConsumerFactory() { + Map props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + props.put(ConsumerConfig.GROUP_ID_CONFIG, "greeting"); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(Greeting.class)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory greetingKafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(greetingConsumerFactory()); + return factory; + } + } diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java index 4f9f9719ee..84d57c9e92 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java @@ -11,6 +11,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; @Configuration public class KafkaProducerConfig { @@ -29,8 +30,21 @@ public class KafkaProducerConfig { @Bean public KafkaTemplate kafkaTemplate() { - KafkaTemplate template = - new KafkaTemplate(producerFactory()); - return template; + return new KafkaTemplate(producerFactory()); } + + @Bean + public ProducerFactory greetingProducerFactory() { + Map configProps = new HashMap(); + configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); + configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + return new DefaultKafkaProducerFactory(configProps); + } + + @Bean + public KafkaTemplate greetingKafkaTemplate() { + return new KafkaTemplate(greetingProducerFactory()); + } + } diff --git a/spring-kafka/src/main/resources/application.properties b/spring-kafka/src/main/resources/application.properties index a1d73b204c..eaf113191e 100644 --- a/spring-kafka/src/main/resources/application.properties +++ b/spring-kafka/src/main/resources/application.properties @@ -1,2 +1,5 @@ kafka.bootstrapAddress=localhost:9092 message.topic.name=baeldung +greeting.topic.name=greeting +filtered.topic.name=filtered +partitioned.topic.name=partitioned \ No newline at end of file From 2d556cd763f0261efb1c2604815656a26a6e83bc Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Fri, 24 Mar 2017 15:29:14 +0100 Subject: [PATCH 165/291] Bael 738 (#1478) * BAEL-724 code for put/patch article * BAEL-724 fix typo * BAEL-728 more generic patch approach --- .../repository/HeavyResourceRepository.java | 10 ++++-- .../controller/HeavyResourceController.java | 18 +++++++---- .../web/dto/HeavyResourceAddressOnly.java | 31 +++++++++++++++++++ .../HeavyResourceControllerTest.java | 19 ++++++++++-- 4 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressOnly.java diff --git a/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java index cff78442d0..6de9e75450 100644 --- a/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java +++ b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java @@ -1,14 +1,20 @@ package org.baeldung.repository; import org.baeldung.web.dto.HeavyResource; -import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; +import org.baeldung.web.dto.HeavyResourceAddressOnly; + +import java.util.Map; public class HeavyResourceRepository { public void save(HeavyResource heavyResource) { } - public void save(HeavyResourceAddressPartialUpdate partialUpdate) { + public void save(HeavyResourceAddressOnly partialUpdate) { + + } + + public void save(Map updates, String id) { } } diff --git a/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java index a2d5cfbd7b..f2c4ffaa51 100644 --- a/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java +++ b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java @@ -3,13 +3,12 @@ package org.baeldung.web.controller; import org.baeldung.repository.HeavyResourceRepository; import org.baeldung.web.dto.HeavyResource; -import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; +import org.baeldung.web.dto.HeavyResourceAddressOnly; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; @RestController public class HeavyResourceController { @@ -23,9 +22,16 @@ public class HeavyResourceController { } @RequestMapping(value = "/heavy", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity partialUpdateName(@RequestBody HeavyResourceAddressPartialUpdate partialUpdate) { + public ResponseEntity partialUpdateName(@RequestBody HeavyResourceAddressOnly partialUpdate) { heavyResourceRepository.save(partialUpdate); return ResponseEntity.ok("resource address updated"); } + @RequestMapping(value = "/heavy/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity partialUpdateGeneric(@RequestBody Map updates, + @PathVariable("id") String id) { + heavyResourceRepository.save(updates, id); + return ResponseEntity.ok("resource updated"); + } + } diff --git a/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressOnly.java b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressOnly.java new file mode 100644 index 0000000000..f96347d60c --- /dev/null +++ b/spring-rest/src/main/java/org/baeldung/web/dto/HeavyResourceAddressOnly.java @@ -0,0 +1,31 @@ +package org.baeldung.web.dto; + + +public class HeavyResourceAddressOnly { + private Integer id; + private String address; + + public HeavyResourceAddressOnly() { + } + + public HeavyResourceAddressOnly(Integer id, String address) { + this.id = id; + this.address = address; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java index e68506701d..e283c5f5f6 100644 --- a/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java +++ b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java @@ -3,7 +3,7 @@ package org.baeldung.web.controller; import com.fasterxml.jackson.databind.ObjectMapper; import org.baeldung.config.WebConfig; import org.baeldung.web.dto.HeavyResource; -import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; +import org.baeldung.web.dto.HeavyResourceAddressOnly; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,6 +16,8 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +import java.util.HashMap; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -47,10 +49,21 @@ public class HeavyResourceControllerTest { } @Test - public void givenNewAddressOfResource_whenExecutePutRequest_thenUpdateResourcePartially() throws Exception { + public void givenNewAddressOfResource_whenExecutePatchRequest_thenUpdateResourcePartially() throws Exception { mockMvc.perform(patch("/heavy") .contentType(MediaType.APPLICATION_JSON_VALUE) - .content(objectMapper.writeValueAsString(new HeavyResourceAddressPartialUpdate(1, "5th avenue"))) + .content(objectMapper.writeValueAsString(new HeavyResourceAddressOnly(1, "5th avenue"))) + ).andExpect(status().isOk()); + } + + @Test + public void givenNewAddressOfResource_whenExecutePatchGeneric_thenUpdateResourcePartially() throws Exception { + HashMap updates = new HashMap<>(); + updates.put("address", "5th avenue"); + + mockMvc.perform(patch("/heavy/1") + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(objectMapper.writeValueAsString(updates)) ).andExpect(status().isOk()); } From 94e1fc2da631a7d49837fec8aa548f4254dfd323 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Fri, 24 Mar 2017 15:52:46 +0100 Subject: [PATCH 166/291] Remove unused tests --- .../org/baeldung/boot/FooComponentTests.java | 70 ------------------- .../org/baeldung/boot/FooIntegrationTest.java | 43 ------------ .../java/org/baeldung/boot/FooJPATest.java | 34 --------- .../java/org/baeldung/boot/FooJsonTest.java | 35 ---------- 4 files changed, 182 deletions(-) delete mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java delete mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java delete mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java delete mode 100644 spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java b/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java deleted file mode 100644 index 72ccc0bfb8..0000000000 --- a/spring-boot/src/test/java/org/baeldung/boot/FooComponentTests.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.baeldung.boot; - -import org.baeldung.boot.components.FooService; -import org.baeldung.boot.model.Foo; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.doReturn; - -@RunWith(SpringRunner.class) -@SpringBootTest( - classes = DemoApplication.class, - webEnvironment = WebEnvironment.RANDOM_PORT) -public class FooComponentTests { - - @Autowired - private TestRestTemplate testRestTemplate; - - @SpyBean - private FooService fooService; - - @Before - public void init() throws Exception { - Foo foo = new Foo(); - foo.setId(5); - foo.setName("MOCKED_FOO"); - - doReturn(foo).when(fooService).getFooWithId(anyInt()); - - // doCallRealMethod().when(fooComponent).getFooWithName(anyString()); - } - - @Test - public void givenInquiryingFooWithId_whenFooComponentIsMocked_thenAssertMockedResult() { - Map pathVariables = new HashMap<>(); - pathVariables.put("id", "1"); - ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); - - assertNotNull(fooResponse); - assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); - assertEquals(5, fooResponse.getBody().getId().longValue()); - assertEquals("MOCKED_FOO", fooResponse.getBody().getName()); - } - - @Test - public void givenInquiryingFooWithName_whenFooComponentIsMocked_thenAssertMockedResult() { - Map pathVariables = new HashMap<>(); - pathVariables.put("name", "Foo_Name"); - ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); - - assertNotNull(fooResponse); - assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); - assertEquals(1, fooResponse.getBody().getId().longValue()); - } -} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java deleted file mode 100644 index 932cce26d5..0000000000 --- a/spring-boot/src/test/java/org/baeldung/boot/FooIntegrationTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.baeldung.boot; -import java.util.HashMap; -import java.util.Map; - -import org.baeldung.boot.DemoApplication; -import org.baeldung.boot.model.Foo; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes=DemoApplication.class,webEnvironment = WebEnvironment.RANDOM_PORT) -public class FooIntegrationTest { - - @Autowired - private TestRestTemplate testRestTemplate; - - - @Test - public void givenInquiryingFooWithId_whenIdIsValid_thenHttpStatusOK(){ - Map pathVariables = new HashMap(); - pathVariables.put("id", "1"); - ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); - Assert.assertNotNull(fooResponse); - Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); - } - - @Test - public void givenInquiryingFooWithName_whenNameIsValid_thenHttpStatusOK(){ - Map pathVariables = new HashMap(); - pathVariables.put("name", "Foo_Name"); - ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); - Assert.assertNotNull(fooResponse); - Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); - } -} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java b/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java deleted file mode 100644 index c29aa64e6c..0000000000 --- a/spring-boot/src/test/java/org/baeldung/boot/FooJPATest.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.baeldung.boot; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import org.baeldung.boot.model.Foo; -import org.baeldung.boot.repository.FooRepository; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@DataJpaTest -public class FooJPATest { - - @Autowired - private TestEntityManager entityManager; - - @Autowired - private FooRepository repository; - - @Test - public void findFooByName() { - this.entityManager.persist(new Foo("Foo_Name_2")); - Foo foo = this.repository.findByName("Foo_Name_2"); - assertNotNull(foo); - assertEquals("Foo_Name_2",foo.getName()); - // Due to having Insert query for Foo with Id 1, so TestEntityManager generates new Id of 2 - assertEquals(2l,foo.getId().longValue()); - } -} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java b/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java deleted file mode 100644 index 2789ed0a8c..0000000000 --- a/spring-boot/src/test/java/org/baeldung/boot/FooJsonTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.baeldung.boot; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.baeldung.boot.model.Foo; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.json.JsonTest; -import org.springframework.boot.test.json.JacksonTester; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@JsonTest -public class FooJsonTest { - - @Autowired - private JacksonTester json; - - - @Test - public void testSerialize() throws Exception { - Foo foo = new Foo(3, "Foo_Name_3"); - assertThat(this.json.write(foo)).isEqualToJson("expected.json"); - assertThat(this.json.write(foo)).hasJsonPathStringValue("@.name"); - assertThat(this.json.write(foo)).extractingJsonPathStringValue("@.name").isEqualTo("Foo_Name_3"); - } - - @Test - public void testDeserialize() throws Exception { - String content = "{\"id\":4,\"name\":\"Foo_Name_4\"}"; - assertThat(this.json.parseObject(content).getName()).isEqualTo("Foo_Name_4"); - assertThat(this.json.parseObject(content).getId()==4); - } -} \ No newline at end of file From ae52b822554f52224129d8da35e3338f958865d8 Mon Sep 17 00:00:00 2001 From: pivovarit Date: Fri, 24 Mar 2017 16:00:05 +0100 Subject: [PATCH 167/291] mvn test --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 120d365569..7737fd4b08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: java -install: travis_wait 60 mvn -q clean install +install: travis_wait 60 mvn -q test before_script: - echo "MAVEN_OPTS='-Xmx2048M -Xss128M -XX:MaxPermSize=2048M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseGCOverheadLimit'" > ~/.mavenrc From cd0873751c7663c93b9f86199ba9af4e09e7d61d Mon Sep 17 00:00:00 2001 From: pivovarit Date: Fri, 24 Mar 2017 16:03:20 +0100 Subject: [PATCH 168/291] add testing profile --- spring-security-mvc-login/pom.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spring-security-mvc-login/pom.xml b/spring-security-mvc-login/pom.xml index 3809dc9f26..f208c74dc4 100644 --- a/spring-security-mvc-login/pom.xml +++ b/spring-security-mvc-login/pom.xml @@ -200,11 +200,9 @@ ${maven-surefire-plugin.version} - + **/*IntegrationTest.java + **/*LiveTest.java - - -
From d0b0debd062018d8fa6106f063a9b89898460d5b Mon Sep 17 00:00:00 2001 From: pivovarit Date: Fri, 24 Mar 2017 16:17:34 +0100 Subject: [PATCH 169/291] Exclude integration tests --- apache-poi/temp.xlsx | Bin 3492 -> 3492 bytes core-java/pom.xml | 1 - ...CountdownLatchExampleIntegrationTest.java} | 2 +- ...va => JavaProcessUnitIntegrationTest.java} | 2 +- ...dPoolInParallelStreamIntegrationTest.java} | 76 +++++++++--------- ...XmlApplicationContextIntegrationTest.java} | 14 ++-- spring-data-rest/pom.xml | 13 ++- ...ringDataRelationshipsIntegrationTest.java} | 2 +- ...ringDataRestValidatorIntegrationTest.java} | 19 +++-- spring-security-cache-control/pom.xml | 16 ++++ spring-security-mvc-login/pom.xml | 2 - xmlunit2/pom.xml | 12 ++- 12 files changed, 96 insertions(+), 63 deletions(-) rename core-java/src/test/java/com/baeldung/concurrent/countdownlatch/{CountdownLatchExampleTest.java => CountdownLatchExampleIntegrationTest.java} (98%) rename core-java/src/test/java/org/baeldung/java/shell/{JavaProcessUnitTest.java => JavaProcessUnitIntegrationTest.java} (98%) rename core-java/src/test/java/org/baeldung/java/streams/{ThreadPoolInParallelStreamTest.java => ThreadPoolInParallelStreamIntegrationTest.java} (93%) rename spring-core/src/test/java/com/baeldung/applicationcontext/{ClasspathXmlApplicationContextTest.java => ClasspathXmlApplicationContextIntegrationTest.java} (97%) rename spring-data-rest/src/test/java/com/baeldung/relationships/{SpringDataRelationshipsTest.java => SpringDataRelationshipsIntegrationTest.java} (98%) rename spring-data-rest/src/test/java/com/baeldung/validator/{SpringDataRestValidatorTest.java => SpringDataRestValidatorIntegrationTest.java} (98%) diff --git a/apache-poi/temp.xlsx b/apache-poi/temp.xlsx index cbea3a410d193a848a5321af8e311bcf61f7160f..12a9b2656c24c1605df94f1a00c1f792a580f154 100644 GIT binary patch delta 460 zcmZ1?y+oQfz?+#xgn@&DgW*79#YSEkMrI(rS%DmQx=gyeR8`p2OU13g<4GuJ#h$ggec8*Dd~TU>w9kC)$`)mhp}fBCbUK_uR8*UW+g z%qL8wB7STzoc#V|a%JV!cLBiyRnsOKX`AWVCYBuLs9g79{okWMLM5)p9Py~~_+Eb9 zSbfK~$z1g>5}FO{q7cRm4rusp z=Uf5_-#BhFaQIH=wgb~QxUD&W;q3)7eX=x}_~@y5bkUalycw)P z0um05eDf~!Op-Ti2>y4!wQ|!0_xt)+Ec$LnoQc`fF=_ej*}s4O*mC{yd!~Y#pHI>b zG4d+}nr!%xn5=ex^6^KXR^5DDHT81tEOAZS{1J*)MTRAd(% zzWY_3MepqrmHJ8RCi@3?vvZiJ)SIe_8q1u}iIG> org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} **/*IntegrationTest.java diff --git a/core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleTest.java b/core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleIntegrationTest.java similarity index 98% rename from core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleTest.java rename to core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleIntegrationTest.java index 7bb2d4bb70..fc343e4cee 100644 --- a/core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleTest.java +++ b/core-java/src/test/java/com/baeldung/concurrent/countdownlatch/CountdownLatchExampleIntegrationTest.java @@ -12,7 +12,7 @@ import java.util.stream.Stream; import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; -public class CountdownLatchExampleTest { +public class CountdownLatchExampleIntegrationTest { @Test public void whenParallelProcessing_thenMainThreadWillBlockUntilCompletion() throws InterruptedException { // Given diff --git a/core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitTest.java b/core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitIntegrationTest.java similarity index 98% rename from core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitTest.java rename to core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitIntegrationTest.java index 2c330c513d..2e38886271 100644 --- a/core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitTest.java +++ b/core-java/src/test/java/org/baeldung/java/shell/JavaProcessUnitIntegrationTest.java @@ -7,7 +7,7 @@ import java.io.*; import java.util.concurrent.Executors; import java.util.function.Consumer; -public class JavaProcessUnitTest { +public class JavaProcessUnitIntegrationTest { private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().startsWith("windows"); private static class StreamGobbler implements Runnable { diff --git a/core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamTest.java b/core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamIntegrationTest.java similarity index 93% rename from core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamTest.java rename to core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamIntegrationTest.java index c2eb1cff5d..42e85fc586 100644 --- a/core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamTest.java +++ b/core-java/src/test/java/org/baeldung/java/streams/ThreadPoolInParallelStreamIntegrationTest.java @@ -1,38 +1,38 @@ -package org.baeldung.java.streams; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.stream.Collectors; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ThreadPoolInParallelStreamTest { - - @Test - public void giveRangeOfLongs_whenSummedInParallel_shouldBeEqualToExpectedTotal() throws InterruptedException, ExecutionException { - long firstNum = 1; - long lastNum = 1_000_000; - - List aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList()); - - ForkJoinPool customThreadPool = new ForkJoinPool(4); - long actualTotal = customThreadPool.submit(() -> aList.parallelStream().reduce(0L, Long::sum)).get(); - - assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal); - } - - @Test - public void givenList_whenCallingParallelStream_shouldBeParallelStream() { - List aList = new ArrayList<>(); - Stream parallelStream = aList.parallelStream(); - - assertTrue(parallelStream.isParallel()); - } -} +package org.baeldung.java.streams; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.stream.Collectors; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ThreadPoolInParallelStreamIntegrationTest { + + @Test + public void giveRangeOfLongs_whenSummedInParallel_shouldBeEqualToExpectedTotal() throws InterruptedException, ExecutionException { + long firstNum = 1; + long lastNum = 1_000_000; + + List aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList()); + + ForkJoinPool customThreadPool = new ForkJoinPool(4); + long actualTotal = customThreadPool.submit(() -> aList.parallelStream().reduce(0L, Long::sum)).get(); + + assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal); + } + + @Test + public void givenList_whenCallingParallelStream_shouldBeParallelStream() { + List aList = new ArrayList<>(); + Stream parallelStream = aList.parallelStream(); + + assertTrue(parallelStream.isParallel()); + } +} diff --git a/spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextTest.java b/spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextIntegrationTest.java similarity index 97% rename from spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextTest.java rename to spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextIntegrationTest.java index 8ee280a2e8..d49f63aea6 100644 --- a/spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextTest.java +++ b/spring-core/src/test/java/com/baeldung/applicationcontext/ClasspathXmlApplicationContextIntegrationTest.java @@ -1,18 +1,18 @@ package com.baeldung.applicationcontext; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import java.util.List; -import java.util.Locale; - import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.MessageSource; import org.springframework.context.support.ClassPathXmlApplicationContext; -public class ClasspathXmlApplicationContextTest { +import java.util.List; +import java.util.Locale; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; + +public class ClasspathXmlApplicationContextIntegrationTest { @Test public void testBasicUsage() { ApplicationContext context = new ClassPathXmlApplicationContext("classpathxmlapplicationcontext-example.xml"); diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index 1845d60e94..1e1ec02e96 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.baeldung - intro-spring-data-rest + spring-data-rest 1.0 jar @@ -56,6 +56,17 @@ org.springframework.boot spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + +
diff --git a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsIntegrationTest.java similarity index 98% rename from spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java rename to spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsIntegrationTest.java index 43b5dd7da6..e3fe60d487 100644 --- a/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/relationships/SpringDataRelationshipsIntegrationTest.java @@ -24,7 +24,7 @@ import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringDataRestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT) -public class SpringDataRelationshipsTest { +public class SpringDataRelationshipsIntegrationTest { @Autowired private TestRestTemplate template; diff --git a/spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorTest.java b/spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorIntegrationTest.java similarity index 98% rename from spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorTest.java rename to spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorIntegrationTest.java index 300fc081d3..bc321bc686 100644 --- a/spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorTest.java +++ b/spring-data-rest/src/test/java/com/baeldung/validator/SpringDataRestValidatorIntegrationTest.java @@ -1,11 +1,8 @@ package com.baeldung.validator; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; - +import com.baeldung.SpringDataRestApplication; +import com.baeldung.models.WebsiteUser; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,14 +14,16 @@ import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; -import com.baeldung.SpringDataRestApplication; -import com.baeldung.models.WebsiteUser; -import com.fasterxml.jackson.databind.ObjectMapper; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = SpringDataRestApplication.class) @WebAppConfiguration -public class SpringDataRestValidatorTest { +public class SpringDataRestValidatorIntegrationTest { public static final String URL = "http://localhost"; private MockMvc mockMvc; diff --git a/spring-security-cache-control/pom.xml b/spring-security-cache-control/pom.xml index c30b0cd1aa..f25e85012e 100644 --- a/spring-security-cache-control/pom.xml +++ b/spring-security-cache-control/pom.xml @@ -85,4 +85,20 @@ 2.9.0 + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + \ No newline at end of file diff --git a/spring-security-mvc-login/pom.xml b/spring-security-mvc-login/pom.xml index f208c74dc4..b3431da7dc 100644 --- a/spring-security-mvc-login/pom.xml +++ b/spring-security-mvc-login/pom.xml @@ -197,7 +197,6 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} **/*IntegrationTest.java @@ -266,7 +265,6 @@ 3.6.0 2.6 - 2.19.1 2.7 1.6.1 diff --git a/xmlunit2/pom.xml b/xmlunit2/pom.xml index d4364292d6..3b659c49c1 100644 --- a/xmlunit2/pom.xml +++ b/xmlunit2/pom.xml @@ -17,6 +17,16 @@ 1.8 + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + @@ -55,6 +65,6 @@ 3.6.0 - + From f673acbb47748a7f7aecfd89ebe000d8a20649bd Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 24 Mar 2017 16:44:28 +0100 Subject: [PATCH 170/291] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7737fd4b08..bcff16f5f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,5 @@ cache: directories: - .autoconf - $HOME/.m2 + From 319dd2653a073f310db05b6121696ebfa7049968 Mon Sep 17 00:00:00 2001 From: Danil Kornishev Date: Fri, 24 Mar 2017 11:55:27 -0400 Subject: [PATCH 171/291] Spring State Machine (#1424) * Neo4j cleanup * Neo4j cleanup * Neo4j cleanup x2 * State Machine Init * cleanup * White background, Java Util Logging * Change to Logging * Static import of asserts. rename test methods --- pom.xml | 5 +- spring-state-machine/bpmn/forkjoin.bpmn | 116 ++++++++++++++++++ spring-state-machine/bpmn/img/forkjoin.png | Bin 0 -> 50788 bytes spring-state-machine/bpmn/img/simple.png | Bin 0 -> 22706 bytes spring-state-machine/bpmn/simple.bpmn | 76 ++++++++++++ spring-state-machine/pom.xml | 31 +++++ .../ApplicationReviewEvents.java | 5 + .../ApplicationReviewStates.java | 5 + .../ForkJoinStateMachineConfiguration.java | 74 +++++++++++ ...HierarchicalStateMachineConfiguration.java | 47 +++++++ .../JunctionStateMachineConfiguration.java | 60 +++++++++ .../SimpleEnumStateMachineConfiguration.java | 53 ++++++++ .../SimpleStateMachineConfiguration.java | 105 ++++++++++++++++ .../config/StateMachineListener.java | 16 +++ .../ForkJoinStateMachineTest.java | 45 +++++++ .../HierarchicalStateMachineTest.java | 37 ++++++ .../JunctionStateMachineTest.java | 24 ++++ .../statemachine/StateEnumMachineTest.java | 33 +++++ .../statemachine/StateMachineBuilderTest.java | 35 ++++++ .../spring/statemachine/StateMachineTest.java | 47 +++++++ 20 files changed, 813 insertions(+), 1 deletion(-) create mode 100644 spring-state-machine/bpmn/forkjoin.bpmn create mode 100644 spring-state-machine/bpmn/img/forkjoin.png create mode 100644 spring-state-machine/bpmn/img/simple.png create mode 100644 spring-state-machine/bpmn/simple.bpmn create mode 100644 spring-state-machine/pom.xml create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java diff --git a/pom.xml b/pom.xml index 15e0e3322e..7c1cacbd33 100644 --- a/pom.xml +++ b/pom.xml @@ -188,6 +188,7 @@ spring-sleuth spring-social-login spring-spel + spring-state-machine spring-thymeleaf spring-userservice spring-zuul @@ -210,7 +211,9 @@ rabbitmq vertx - + + + diff --git a/spring-state-machine/bpmn/forkjoin.bpmn b/spring-state-machine/bpmn/forkjoin.bpmn new file mode 100644 index 0000000000..0cb060f74b --- /dev/null +++ b/spring-state-machine/bpmn/forkjoin.bpmn @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-state-machine/bpmn/img/forkjoin.png b/spring-state-machine/bpmn/img/forkjoin.png new file mode 100644 index 0000000000000000000000000000000000000000..642ab6949d18b49012529d7c5b9b14f909c9d701 GIT binary patch literal 50788 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�gf@SIUg-QO`umQ3S)QlWiV3@kS`RLu_ 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 D__yV@ literal 0 HcmV?d00001 diff --git a/spring-state-machine/bpmn/img/simple.png b/spring-state-machine/bpmn/img/simple.png new file mode 100644 index 0000000000000000000000000000000000000000..7a79bf1d895a401b2b59d4b093e770f3546bc3d3 GIT binary patch literal 22706 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/spring-state-machine/bpmn/simple.bpmn b/spring-state-machine/bpmn/simple.bpmn new file mode 100644 index 0000000000..8ed463e9f9 --- /dev/null +++ b/spring-state-machine/bpmn/simple.bpmn @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-state-machine/pom.xml b/spring-state-machine/pom.xml new file mode 100644 index 0000000000..5393626083 --- /dev/null +++ b/spring-state-machine/pom.xml @@ -0,0 +1,31 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + baeldung-spring-state-machine + + 1.8 + 1.8 + + + + + org.springframework.statemachine + spring-statemachine-core + 1.2.3.RELEASE + + + junit + junit + 4.11 + test + + + \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java new file mode 100644 index 0000000000..971fc5dde7 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java @@ -0,0 +1,5 @@ +package com.baeldung.spring.stateMachine.applicationReview; + +public enum ApplicationReviewEvents { + APPROVE, REJECT +} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java new file mode 100644 index 0000000000..1df2db1f86 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java @@ -0,0 +1,5 @@ +package com.baeldung.spring.stateMachine.applicationReview; + +public enum ApplicationReviewStates { + PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED +} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java new file mode 100644 index 0000000000..c55104a627 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java @@ -0,0 +1,74 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +@Configuration +@EnableStateMachine +public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .fork("SFork") + .join("SJoin") + .end("SF") + .and() + .withStates() + .parent("SFork") + .initial("Sub1-1") + .end("Sub1-2") + .and() + .withStates() + .parent("SFork") + .initial("Sub2-1") + .end("Sub2-2"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SFork").event("E1") + .and().withExternal() + .source("Sub1-1").target("Sub1-2").event("sub1") + .and().withExternal() + .source("Sub2-1").target("Sub2-2").event("sub2") + .and() + .withFork() + .source("SFork") + .target("Sub1-1") + .target("Sub2-1") + .and() + .withJoin() + .source("Sub1-2") + .source("Sub2-2") + .target("SJoin"); + } + + @Bean + public Guard mediumGuard() { + return (ctx) -> false; + } + + @Bean + public Guard highGuard() { + return (ctx) -> false; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java new file mode 100644 index 0000000000..708dbd3077 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java @@ -0,0 +1,47 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; + +@Configuration +@EnableStateMachine +public class HierarchicalStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .state("SI") + .end("SF") + .and() + .withStates() + .parent("SI") + .initial("SUB1") + .state("SUB2") + .end("SUBEND"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SF").event("end") + .and().withExternal() + .source("SUB1").target("SUB2").event("se1") + .and().withExternal() + .source("SUB2").target("SUBEND").event("s-end"); + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java new file mode 100644 index 0000000000..e1bae10fb7 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java @@ -0,0 +1,60 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +@Configuration +@EnableStateMachine +public class JunctionStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .junction("SJ") + .state("high") + .state("medium") + .state("low") + .end("SF"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SJ").event("E1") + .and() + .withJunction() + .source("SJ") + .first("high", highGuard()) + .then("medium", mediumGuard()) + .last("low") + .and().withExternal() + .source("low").target("SF").event("end"); + } + + @Bean + public Guard mediumGuard() { + return (ctx) -> false; + } + + @Bean + public Guard highGuard() { + return (ctx) -> false; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java new file mode 100644 index 0000000000..4e11851644 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java @@ -0,0 +1,53 @@ +package com.baeldung.spring.stateMachine.config; + +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +import java.util.Arrays; +import java.util.HashSet; + +@Configuration +@EnableStateMachine +public class SimpleEnumStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(ApplicationReviewStates.PEER_REVIEW) + .state(ApplicationReviewStates.PRINCIPAL_REVIEW) + .end(ApplicationReviewStates.APPROVED) + .end(ApplicationReviewStates.REJECTED); + + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.PRINCIPAL_REVIEW).event(ApplicationReviewEvents.APPROVE) + .and().withExternal() + .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.APPROVED).event(ApplicationReviewEvents.APPROVE) + .and().withExternal() + .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT) + .and().withExternal() + .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT); + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java new file mode 100644 index 0000000000..fe4e0f82ce --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -0,0 +1,105 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.logging.Logger; + +@Configuration +@EnableStateMachine +public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter { + + public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .end("SF") + .states(new HashSet<>(Arrays.asList("S1", "S2"))) + .state("S4", executeAction(), errorAction()) + .stateEntry("S3", entryAction()) + .stateDo("S3", executeAction()) + .stateExit("S3", exitAction()); + + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("S1").event("E1").action(initAction()) + .and().withExternal() + .source("S1").target("S2").event("E2") + .and().withExternal() + .source("SI").target("S3").event("E3") + .and().withExternal() + .source("S3").target("S4").event("E4").guard(simpleGuard()) + .and().withExternal() + .source("S2").target("SF").event("end"); + } + + @Bean + public Guard simpleGuard() { + return (ctx) -> { + int approvalCount = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); + return approvalCount > 0; + }; + } + + @Bean + public Action entryAction() { + return (ctx) -> { + LOGGER.info("Entry " + ctx.getTarget().getId()); + }; + } + + @Bean + public Action executeAction() { + return (ctx) -> { + LOGGER.info("Do " + ctx.getTarget().getId()); + int approvals = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); + approvals++; + ctx.getExtendedState().getVariables().put("approvalCount", approvals); + }; + } + + @Bean + public Action exitAction() { + return (ctx) -> { + LOGGER.info("Exit " + ctx.getSource().getId() + " -> " + ctx.getTarget().getId()); + }; + } + + @Bean + public Action errorAction() { + return (ctx) -> { + LOGGER.info("Error " + ctx.getSource().getId() + ctx.getException()); + }; + } + + @Bean + public Action initAction() { + return (ctx) -> { + LOGGER.info(ctx.getTarget().getId()); + }; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java new file mode 100644 index 0000000000..bb7859c683 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import org.springframework.statemachine.state.State; + +import java.util.logging.Logger; + +public class StateMachineListener extends StateMachineListenerAdapter { + + public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); + + @Override + public void stateChanged(State from, State to) { + LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java new file mode 100644 index 0000000000..416da5f0fe --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java @@ -0,0 +1,45 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.ForkJoinStateMachineConfiguration; + +public class ForkJoinStateMachineTest { + + @Test + public void whenForkStateEntered_thenMultipleSubStatesEntered() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + boolean success = stateMachine.sendEvent("E1"); + + assertTrue(success); + + assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); + } + + @Test + public void whenAllConfiguredJoinEntryStatesAreEntered_thenTransitionToJoinState() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + boolean success = stateMachine.sendEvent("E1"); + + assertTrue(success); + + assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); + + assertTrue(stateMachine.sendEvent("sub1")); + assertTrue(stateMachine.sendEvent("sub2")); + assertEquals("SJoin", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java new file mode 100644 index 0000000000..3557a63211 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.HierarchicalStateMachineConfiguration; + +public class HierarchicalStateMachineTest { + + @Test + public void whenTransitionToSubMachine_thenSubStateIsEntered() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(HierarchicalStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + + assertEquals(Arrays.asList("SI", "SUB1"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("se1"); + + assertEquals(Arrays.asList("SI", "SUB2"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("s-end"); + + assertEquals(Arrays.asList("SI", "SUBEND"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("end"); + + assertEquals(1, stateMachine.getState().getIds().size()); + assertEquals("SF", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java new file mode 100644 index 0000000000..d0c1225c9b --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.stateMachine; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.JunctionStateMachineConfiguration; + +public class JunctionStateMachineTest { + + @Test + public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JunctionStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + stateMachine.sendEvent("E1"); + Assert.assertEquals("low", stateMachine.getState().getId()); + + stateMachine.sendEvent("end"); + Assert.assertEquals("SF", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java new file mode 100644 index 0000000000..1fd7bd85f0 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java @@ -0,0 +1,33 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; +import com.baeldung.spring.stateMachine.config.SimpleEnumStateMachineConfiguration; + +public class StateEnumMachineTest { + + private StateMachine stateMachine; + + @Before + public void setUp() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleEnumStateMachineConfiguration.class); + stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + } + + @Test + public void whenStateMachineConfiguredWithEnums_thenStateMachineAcceptsEnumEvents() { + assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.APPROVE)); + assertEquals(ApplicationReviewStates.PRINCIPAL_REVIEW, stateMachine.getState().getId()); + assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.REJECT)); + assertEquals(ApplicationReviewStates.REJECTED, stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java new file mode 100644 index 0000000000..cdd1e951e0 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java @@ -0,0 +1,35 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.config.StateMachineBuilder; + +public class StateMachineBuilderTest { + + @Test + public void whenUseStateMachineBuilder_thenBuildSuccessAndMachineWorks() throws Exception { + StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); + builder.configureStates().withStates() + .initial("SI") + .state("S1") + .end("SF"); + + builder.configureTransitions() + .withExternal() + .source("SI").target("S1").event("E1") + .and().withExternal() + .source("S1").target("SF").event("E2"); + + StateMachine machine = builder.build(); + + machine.start(); + + machine.sendEvent("E1"); + assertEquals("S1", machine.getState().getId()); + + machine.sendEvent("E2"); + assertEquals("SF", machine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java new file mode 100644 index 0000000000..1b442bf994 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java @@ -0,0 +1,47 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.SimpleStateMachineConfiguration; + +public class StateMachineTest { + + private StateMachine stateMachine; + + @Before + public void setUp() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleStateMachineConfiguration.class); + stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + } + + @Test + public void whenSimpleStringStateMachineEvents_thenEndState() { + assertEquals("SI", stateMachine.getState().getId()); + + stateMachine.sendEvent("E1"); + assertEquals("S1", stateMachine.getState().getId()); + + stateMachine.sendEvent("E2"); + assertEquals("S2", stateMachine.getState().getId()); + + stateMachine.sendEvent("end"); + assertEquals("SF", stateMachine.getState().getId()); + + } + + @Test + public void whenSimpleStringMachineActionState_thenActionExecuted() { + stateMachine.sendEvent("E3"); + assertEquals("S3", stateMachine.getState().getId()); + + stateMachine.sendEvent("E4"); + assertEquals("S4", stateMachine.getState().getId()); + assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount")); + } +} From 3140ea166d05c59b605eb3ac0b5d55a116344c6e Mon Sep 17 00:00:00 2001 From: bs-santosh Date: Fri, 24 Mar 2017 21:49:32 +0530 Subject: [PATCH 172/291] Bs santosh spring mybatis (#1479) * Spring and MyBatis integration maven project Complete article is available in http://inprogress.baeldung.com/wp-admin/post.php * Spring-MyBatis integration example This code demonstrates how to use MyBatis in Sring environment. Full details could be found in article http://inprogress.baeldung.com/?p=31706&preview=true --- spring-mybatis/pom.xml | 62 +++++++++ .../application/SpringMyBatisApplication.java | 48 +++++++ .../mybatis/controller/StudentController.java | 60 ++++++++ .../spring/mybatis/mappers/StudentMapper.java | 19 +++ .../spring/mybatis/model/Student.java | 55 ++++++++ .../spring/mybatis/model/StudentLogin.java | 18 +++ .../mybatis/service/StudentService.java | 9 ++ .../mybatis/service/StudentServiceImpl.java | 40 ++++++ .../src/main/resources/mybatis-spring.xml | 54 ++++++++ .../webapp/WEB-INF/conf/mybatis-spring.xml | 51 +++++++ .../src/main/webapp/WEB-INF/jsp/failure.jsp | 36 +++++ .../src/main/webapp/WEB-INF/jsp/login.jsp | 81 +++++++++++ .../src/main/webapp/WEB-INF/jsp/signup.jsp | 130 ++++++++++++++++++ .../src/main/webapp/WEB-INF/jsp/success.jsp | 35 +++++ .../lib/mysql-connector-java-5.1.40-bin.jar | Bin 0 -> 990927 bytes .../src/main/webapp/WEB-INF/web.xml | 21 +++ spring-mybatis/src/main/webapp/index.jsp | 34 +++++ 17 files changed, 753 insertions(+) create mode 100644 spring-mybatis/pom.xml create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/application/SpringMyBatisApplication.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/controller/StudentController.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/mappers/StudentMapper.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/Student.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/StudentLogin.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentService.java create mode 100644 spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentServiceImpl.java create mode 100644 spring-mybatis/src/main/resources/mybatis-spring.xml create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/conf/mybatis-spring.xml create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/jsp/failure.jsp create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/jsp/login.jsp create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/jsp/signup.jsp create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/jsp/success.jsp create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/lib/mysql-connector-java-5.1.40-bin.jar create mode 100644 spring-mybatis/src/main/webapp/WEB-INF/web.xml create mode 100644 spring-mybatis/src/main/webapp/index.jsp diff --git a/spring-mybatis/pom.xml b/spring-mybatis/pom.xml new file mode 100644 index 0000000000..b0eaab5b3a --- /dev/null +++ b/spring-mybatis/pom.xml @@ -0,0 +1,62 @@ + + 4.0.0 + com.baeldung + spring-mybatis + jar + 0.0.1-SNAPSHOT + spring-mybatis Maven Webapp + http://maven.apache.org + + + org.mybatis + mybatis + 3.1.1 + + + org.mybatis + mybatis-spring + 1.1.1 + + + org.springframework + spring-context-support + 3.1.1.RELEASE + + + org.springframework + spring-test + 3.1.1.RELEASE + test + + + mysql + mysql-connector-java + 5.1.40 + + + javax.servlet + jstl + 1.2 + + + org.springframework + spring-webmvc + 3.2.4.RELEASE + + + javax.servlet + servlet-api + 2.5 + + + junit + junit + 3.8.1 + test + + + + spring-mybatis + + diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/application/SpringMyBatisApplication.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/application/SpringMyBatisApplication.java new file mode 100644 index 0000000000..acfaff2669 --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/application/SpringMyBatisApplication.java @@ -0,0 +1,48 @@ +package com.baeldung.spring.mybatis.application; + +import java.util.Date; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.baeldung.spring.mybatis.model.Student; +import com.baeldung.spring.mybatis.service.StudentService; + +public class SpringMyBatisApplication { + + public static void main(String[] args){ + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("mybatis-spring.xml"); + + StudentService studentService = (StudentService) ctx.getBean("studentService"); + Student student = new Student(); + student.setFirstName("Santosh"); + student.setLastName("B S"); + student.setEmailAddress("santosh.bse@gmail.com"); + student.setPassword("Test123"); + student.setDateOfBirth(new Date()); + student.setUserName("santoshbs1"); + + boolean result = studentService.insertStudent(student); + if(result){ + System.out.println("Student record saved successfully"); + } + else{ + System.out.println("Encountered an error while saving student data"); + } + + final String userName = "santosh"; + Student matchingStudent = studentService.getStudentByUserName(userName); + if(matchingStudent == null){ + System.out.println("No matching student found for User Name - " + userName); + } + else{ + System.out.println("Student Details are as follows : "); + System.out.println("First Name : " + matchingStudent.getFirstName()); + System.out.println("Last Name : " + matchingStudent.getLastName()); + System.out.println("EMail : " + matchingStudent.getEmailAddress()); + System.out.println("DOB : " + matchingStudent.getDateOfBirth()); + System.out.println("User Name : " + matchingStudent.getUserName()); + } + + } + +} diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/controller/StudentController.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/controller/StudentController.java new file mode 100644 index 0000000000..427613f23f --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/controller/StudentController.java @@ -0,0 +1,60 @@ +package com.baeldung.spring.mybatis.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.baeldung.spring.mybatis.model.Student; +import com.baeldung.spring.mybatis.model.StudentLogin; +import com.baeldung.spring.mybatis.service.StudentService; + +@Controller +@SessionAttributes("student") +public class StudentController { + + @Autowired + private StudentService studentService; + + @RequestMapping(value = "/signup", method = RequestMethod.GET) + public String signup(Model model) { + Student student = new Student(); + model.addAttribute("student", student); + return "signup"; + } + + @RequestMapping(value = "/signup", method = RequestMethod.POST) + public String signup(@Validated @ModelAttribute("student") Student student, BindingResult result, ModelMap model) { + if (studentService.getStudentByUserName(student.getUserName())) { + model.addAttribute("message", "User Name exists. Try another user name"); + return "signup"; + } else { + studentService.insertStudent(student); + model.addAttribute("message", "Saved student details"); + return "redirect:login.html"; + } + } + + @RequestMapping(value = "/login", method = RequestMethod.GET) + public String login(Model model) { + StudentLogin studentLogin = new StudentLogin(); + model.addAttribute("studentLogin", studentLogin); + return "login"; + } + + @RequestMapping(value = "/login", method = RequestMethod.POST) + public String login(@ModelAttribute("studentLogin") StudentLogin studentLogin, BindingResult result, ModelMap model) { + boolean found = studentService.getStudentByLogin(studentLogin.getUserName(), studentLogin.getPassword()); + if (found) { + return "success"; + } else { + return "failure"; + } + } +} \ No newline at end of file diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/mappers/StudentMapper.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/mappers/StudentMapper.java new file mode 100644 index 0000000000..cf3584f7b1 --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/mappers/StudentMapper.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.mybatis.mappers; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Select; + +import com.baeldung.spring.mybatis.model.Student; + +public interface StudentMapper { + @Insert("INSERT INTO student(userName, password, firstName,lastName, dateOfBirth, emailAddress) VALUES" + + "(#{userName},#{password}, #{firstName}, #{lastName}, #{dateOfBirth}, #{emailAddress})") + @Options(useGeneratedKeys = true, keyProperty = "id", flushCache = true, keyColumn = "id") + public void insertStudent(Student student); + + @Select("SELECT USERNAME as userName, PASSWORD as password, FIRSTNAME as firstName, LASTNAME as lastName, " + + "DATEOFBIRTH as dateOfBirth, EMAILADDRESS as emailAddress " + "FROM student WHERE userName = #{userName}") + public Student getStudentByUserName(String userName); + +} \ No newline at end of file diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/Student.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/Student.java new file mode 100644 index 0000000000..f33dd44f72 --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/Student.java @@ -0,0 +1,55 @@ +package com.baeldung.spring.mybatis.model; + +import java.util.Date; + +public class Student { + private Long id; + private String userName; + private String firstName; + private String lastName; + private String password; + private String emailAddress; + private Date dateOfBirth; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getFirstName() { + return firstName; + } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + public String getLastName() { + return lastName; + } + public void setLastName(String lastName) { + this.lastName = lastName; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public String getEmailAddress() { + return emailAddress; + } + public void setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + } + public Date getDateOfBirth() { + return dateOfBirth; + } + public void setDateOfBirth(Date dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } +} diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/StudentLogin.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/StudentLogin.java new file mode 100644 index 0000000000..867857b510 --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/model/StudentLogin.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.mybatis.model; + +public class StudentLogin { + private String userName; + private String password; + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } +} diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentService.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentService.java new file mode 100644 index 0000000000..d26115beee --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentService.java @@ -0,0 +1,9 @@ +package com.baeldung.spring.mybatis.service; + +import com.baeldung.spring.mybatis.model.Student; + +public interface StudentService { + public boolean insertStudent(Student student); + public Student getStudentByLogin(String userName, String password); + public Student getStudentByUserName(String userName); +} \ No newline at end of file diff --git a/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentServiceImpl.java b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentServiceImpl.java new file mode 100644 index 0000000000..538e650482 --- /dev/null +++ b/spring-mybatis/src/main/java/com/baeldung/spring/mybatis/service/StudentServiceImpl.java @@ -0,0 +1,40 @@ +package com.baeldung.spring.mybatis.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.spring.mybatis.mappers.StudentMapper; +import com.baeldung.spring.mybatis.model.Student; + +@Service("studentService") +public class StudentServiceImpl implements StudentService { + + @Autowired + private StudentMapper studentMapper; + + @Transactional + public boolean insertStudent(Student student) { + boolean result=false; + try{ + studentMapper.insertStudent(student); + result = true; + } + catch(Exception ex){ + ex.printStackTrace(); + result = false; + } + return result; + } + + public Student getStudentByLogin(String userName, String password) { + Student student = studentMapper.getStudentByUserName(userName); + return student; + } + + public Student getStudentByUserName(String userName) { + Student student = studentMapper.getStudentByUserName(userName); + return student; + } + +} diff --git a/spring-mybatis/src/main/resources/mybatis-spring.xml b/spring-mybatis/src/main/resources/mybatis-spring.xml new file mode 100644 index 0000000000..9f5bab3247 --- /dev/null +++ b/spring-mybatis/src/main/resources/mybatis-spring.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/conf/mybatis-spring.xml b/spring-mybatis/src/main/webapp/WEB-INF/conf/mybatis-spring.xml new file mode 100644 index 0000000000..c8b686358c --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/conf/mybatis-spring.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/jsp/failure.jsp b/spring-mybatis/src/main/webapp/WEB-INF/jsp/failure.jsp new file mode 100644 index 0000000000..66f16d4e09 --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/jsp/failure.jsp @@ -0,0 +1,36 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + +Login Failure + + + + +
+ Login     Signup +
+
+
+

Student Enrollment Login failure

+
+
+
+ + Oh snap! Something is wrong. Change a few things up + and try submitting again. +
+
+
+
+
+ + ">Try + again? + + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/jsp/login.jsp b/spring-mybatis/src/main/webapp/WEB-INF/jsp/login.jsp new file mode 100644 index 0000000000..5a895bb348 --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/jsp/login.jsp @@ -0,0 +1,81 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> + + + + + + + +Student Login + + +
+ Login     Signup +
+ +
+
+
+

Welcome to Online Student Enrollment Application

+

Login to explore the complete features!

+
+
+ +
+
+ +
+
+ Student Enrollment Login Form + + + + + + + + + + + + + + + +
+
+ +      + +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/jsp/signup.jsp b/spring-mybatis/src/main/webapp/WEB-INF/jsp/signup.jsp new file mode 100644 index 0000000000..bc628862f3 --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/jsp/signup.jsp @@ -0,0 +1,130 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + +Student Signup + + + + + +
+ Login     Signup +
+ +
+
+
+

Welcome to Online Student Enrollment Application

+

Login to explore the complete features!

+
+
+ +
+
+ +
+ +
${message}
+
+
+ +
+ +
+ Student Enrollment Signup Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +     + +
+
+
+
+ + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/jsp/success.jsp b/spring-mybatis/src/main/webapp/WEB-INF/jsp/success.jsp new file mode 100644 index 0000000000..7ae37bc241 --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/jsp/success.jsp @@ -0,0 +1,35 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + +Login Success + + + + +
+ Login     Signup +
+ +
+
+

Student Enrollment Login success

+
+
+
+ + Well done! You successfully logged-into the system. + Now you can explore the complete features! +
+
+
+
+
+ ">Login + as different user? + + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/WEB-INF/lib/mysql-connector-java-5.1.40-bin.jar b/spring-mybatis/src/main/webapp/WEB-INF/lib/mysql-connector-java-5.1.40-bin.jar new file mode 100644 index 0000000000000000000000000000000000000000..60bef5cfbfbecf98b7371ba19389fe792be305e0 GIT binary patch literal 990927 zcma%i1CV6fwrzFUwz_QFwr$(Cy34k0ciFaW+h&*X>)iA1efQjV-ix1+8IiGLuG|^1 z#+ZA|HOG{b1OkQx000L7&@W&U2l%%a1OPCAw6GFCwYZE3?Z+qpfZTtDf&=J%g@(TR zMN|R;0APGAMgCg$uTW`z8F3L|MI{<(k;ude+f_Q`?yJ~aUNx;oi5`hLl~sk`)3Z1l zk=`NZ$+#qYDSD`DrPkwiH^zWQ zyrqvb@MC;$ktTP|3NUJZq4QW}yu-+R8m-u+>EuSo7YZ55G%#QprqUgYD|jJ@!b$3= z+v>{J73yZ5zZmaGqCJS^s48@I+K4$Su_J}@w=fZYVYt|({8bh1dCo7 zrC8HNlRyVq5mQum5xx)h2mDKN0{8oc#aJ7b6%x*RuY3BNjhz)}V6H^s2;fWCU>rEj z8k$KBz4BcnDoSIT7!XQ`(8;VMv^pH3Ebt`msSm?1izNVs4#q@)BO#L<+bl1UfL1m) z=`^KwUOSf%owtHHe~ogCsuWma$PB(p?*7@^J7+*qY?MX8YG&h3!$Ym!w$_Km&DWPq zX&d?O6_CSOh6^)^N5L*%cjrgbX!53H+_`cN@4Aa%Sg38OM0U+q*F1?yH;igW)mkmJ zZM_+{4F8E?B}WerrJqP-YqrVxrIw}#ZWa&YXle&f4Ez{xg=qeo6A^yYfk~B@Z#Jw% zV1_D4Fy$*mX0!~bE*;0w1a?k*zd&e|)L@aYV%pXq`29F)!Y?`AuEIR-djQ$ITsE@n z%7X5j0)xuAHW@!a($lVnu-JMae&kndm{k+Ua`JJI)*87bI@26VhVk~rnufk^W(_`l zB)IL+kh!2rqN7PcD)enzRZT;5RmPu9<$l+Bo|2p9j@muu{U^TvClwI?9p8?|4ld?~ z#*VcAj0gV*b?jWa+^N3exW7L5e;aS1@1jrRXm3R$>xQgwJ=seMKeA#CLu1d z=tw?FB}u(25folTOoC!eB1p8+ZM8MJ&G$Wo<6qPR08su9mI8m>%Fx#OUw`I*MtrgR z9}(8>U-$mEIFd2p930?}@W7|W9=~q@0MB2%XZ*Wxk$(;blU9;lLo{jRH}@jlzph zYZON<+QaT`4HxsxHqeut!DJ(OF42R&$>a}HpF3W5+bh~C0GFBsVaz&?@e?{*y`F9Y zeWsXBL>Ivq-`n-@ctOBSL2{oOe+Sz!qBV^V@~0wDi8fNVr` zp*YLUVfvxbZ>r5spB6DwHaw)Bm0%lfMiWHjMSob+2~QIWJ{hvpc+|2J&^*wQ*u zpRoxr0D!bFjFbLfTWVutZ1~^XSfP5Ri@b#41M1?MWDF=aA0p5nVxmrCDP;+rqYR%1 zdR+^drW0%&P~+)nf{JgRejmpqepTABJb15TZ81j#18;ye=b7$vUi@*}#pFGix?=32 z9`mpS=Q-&)=|1(!bM#NPaI*r+}lok&P$$oyxFUkW0~Ey$%1CK>Bc(sk_)CFoR?v^MLhltPEOhvdy-e@X!ki#B zo8=svkh)+?Spf=iaLKu*iVN4ZL=2(d@soC>P+KUZbM1Rlyp)Bbh){6X)9FE+%n_rB zLXsQ(GkJNG{G+dGb(277(-!&hN77D%BK{JXcF%UJhbXafVJ@8PX%tWHni8VZdTkk_ z^$FC zfEPu#u#42l7HlDB0nHHyB{s5iRxqA7IYHiTa{N~B8iDO_=F9$IOd0$FJ?~>CnG?&; zS~QmIgZrTw`iUeUZS!J02PrKHGig)?^_q<8#SLy1nju}eJ7{j|eY7{VVdUokIE7(lZjVHG>AZ zEhXz{Q0>dXMdNQRW7l2jCitlobHjeA!hS)Sk~d_C8z~?85~8T;s4-o_B?kF}qDQN1 zX6jP8Eyvkrhvc|oXV3YRLRUZxb_it~+1o<=3W6f7tfSX_%HLJ%rQo%d+eE2S^|gzP zW7e|xt&_vmIL^xFrR7FhbUMu=6I0dk&a#q-c=V>6px;MfM%s;Qmfy2%)Enat&glC= zhSYufXTFE__#)+tBJQSY$2X{2(1ySWMTdi{AYpE;LGqMus;PCU{s<2tph$^)`^C&0Wv)#qx zjydJ7d0#$ylG|#S+bS0qVFB~ixqL*NhRCtUEAUA?+rUlCy&pkKd4g*A2gFDwPw85s z^1+FU9cJil`U2~i4Q`oR{8TI!?*XQL*}5m~186T)v*mK;nTP=nR7tj|e+uh(e(c=F zmEImA3px6QMz0Bos{Qv+Ph^(^YVL13&@3RR)APt`y^9tRx<5WU)QXX7rN@zH*VV;C zbl_)ak>CL@6Nk8aigJeR_~haYJ!L~I0Gp;qhcC<^skb{p&aJHW@KD>>X!RZ$ey%NT z{g7|%hdI^Z0EAXd`DUT#XQi*EfzjCqy`T=dn-3kx-^3#bwy{0gWvA16MOcDA1$r4l z??u2rWFN&~o8yliJ+nYNU1LBy+(vq%zX{&mn=mB$=uru`mpy+=AC&X$vwKKfd4y?Y ze1-c}=tk-&i?@(8Y{w@9(|9-Bpp_ll6KQ5?MrMkMr{iY|O`giS#Y1D`3|v?OY5^0g zFiSirJ#Zwj5yrAXNZ8*8xcu|10_+kFBEPR{Vh1QW@!Fi*{_R9`&cj>$>TCa z^O}rd=UF(C_zQymGtFsy4Zhrz##uu_hQ#8Llhc$PZhJ@B)F=T&CuGE&IhfAkmO?GZ zs5DynI%?*oR)+AjNBG1wm51&4+6a`Jz-@i>IC_Az6Xmi^mjldGt=gSYNjab;1T}fL zWbeQwt$S@y^(y;HopV_wGW90y{btut_k+AJPei{wqp?7)6C^~cvL@o>yZ=xG$*73I z#a{w14Fmvy;(u2Jicb1Y#tO!ccD6Q-#(!$N$b=P}IX>i|PkU6>p2Bo-Gz|$!O>8g= zjm1WJ;(1{UWR1{(P0mYrEq16z|6?G$p0=OBA%MGnVB5LyrX=R`R01u-ZinNkS8qpC z%RfFoUSRZKR)`SANa=tTp;L)2w`~B+tK*o~k!qMx&L}P!g=EjCP0**ZS8c7v>dKAJ zN}NVB?ZWZp?Z%Wjt)4RQ6{r-1V49JT1*3g&=pt^LoR^M-n|iZbvW`HJC+Yj^Y!+ae zFcd^+f8%*e3AUP7pv4znD$ss zd6*}AE!8|6&PfO9PzX^p)!bsQIyblgiI>xe`*cW}*Hhm-O&s)?nxdB|&gorw?B=yQGQ zq{L1+ox3VyE6~S=Vd3(^iL5>&esf|_gSxz zXM+;Z(MNa0?3^m!IS@HA(jau=9xGMWgh(28<8KPLqCUUC#<@gAKfL>tCWZ^@T?JvW z*q>#mnx>4&aU}*6zJ~^lRDldS5xp2=XO^5ozlb#STjZ$V!ILrl>3#>6lFA-zFquVY z@F8?hX;637NobQT_)ajhWG00GphOcUOyL&3E!pgA90tUiP9|jl8BEG6kT zJDO&03eyCln|y1cdAo@uKR?&DPkle*l+J{)%gNs$WkE;CoQhm{XD#ia8NWG8Wa4Nf zy&uQXQ6Y0B=jv~AH*c!Ap{N0&F#ZO5;HW911*&T7UXeOY!MlNw8cXS`owH1kI^t0s z8?C+k+qc@O^n|yio7_6%r4*`(9$v=$L<>KDVD1U*uL5{IAux~c3+@G9l@#ya!Cg$> z(M-`y-@!;)-_Fk5#*|3G_^WzzH2%jmaT_CJH$__qCu4^{IgqKSZHvf{%v~pkdTdbB z*r-vi6y~*Ry?_S9B9Dk7EL~u}yH_1iJy9FpCaL%tPa7$oZf4;1Ac}ECm5!P_&@XLr zIo{zq$^AHfUbVI51F+naPlPy3f-qo$$iA)^D@zdM7Zz8)0xWHef`amhv0HTUyv_pL zH|l9mrX^eNv3|jH9>r$CUP-G3TA{zzTcNpr7ceAejVYsh_2Yp@{Y7-sMOyI3NQaKy zCCqndskSzE2$e*96-Mj1E#na6uvh4r*16nWDCs#=+u-*`yGOS*f+>SJ`sRiyZN*DL z)A_5^em-JApv$;Das9M$_Zg^^D3EX%(1CS*wd_=qcwD-Ds0kpSVdwBQ?RV{0K6D@F zRU|!JYsnWydW>9)n>77EL?R87rNa+7m)l*2r(9bN4{o!R*C@?&ahK#WBF)KZ=6**- zibgJXW=%w;KEPSb#+>ry#p4+{e@jL?W~#l`uwdxu&(}-l@jXaEk6P)V!tfWO+}7S7 zhtLioYxAk7hr%Io_n9pLf*XHN!^Pc)IG3_~#KOTNUzY{^kBr(~D?cQ4o=ZdWi zJ0`ktsEfE%IzhTfL4kxb4FQ_ME}1QgK&U}RF_!APJ)szj8i^bLOQa4$5a^Q7-F_1> zNkB6gUVv2bZx-oS$t}o6yqti4WHugqQ!0H!nt_Z&8kYt<8vLnf+D-mzM+IJ1KT`#A zx7mBqI_cpy{WEGgSg}MGffv?;BbXX#J2OWK6w9|mQVyIbB3H~S{>Q&6{XYwCbA@#R z=C3?_`BlXKZFTma;QSMWg({k=NUF#mGT>5(BK+|1$3vyKa)1~m5{$#7+ zefud9ndAMbp?)1r_ddUC;IzxjX*1rW6z<%iaL+`R&hE<&&zIYYM^TQfsAkIwg+(Abt|AG zzmD(3v{TmBe&x^{`^JQsOOR|K&e9Q$f7uF)D;V|0UGot9q^ZZ$v5t&YLzLE%?Wuh< zmhjSj@m~J=-8~hru}RAjDSFw9)Y|iE#Czi0GMk{?^oU(h8p7ORsew;io8e1=Fr_nLRIcV;t7VwG zJN@yIRBx9lGdw~RFk=}SWN$-=gU&nyv=kv?JFy#)(yC#mlBv1)G!iO9>aOU_EY z(RiPNPdgc{#E1kz?;zz)I28GB?A^uad6buOqvB|h>pv5n&CKY;8#a1j`x=K*2DK(bxlv#tDPXsQ(DNv=M5+K)1HrQWVvg=wv%^Uzewn;- zjhWkif1o5QYYx?fEK-u%Yn=8G97uPQ99VM`9cXil#vGFHi5H$51xEs-6Eeb8x#8h~ zwKP>zWZ?_ZGEoYG!Z1VcIUj7Gf%=|D}T0GLq5h& zsylrIrKq%?WV{rHS)Vlmt+q%(JhmG|)w*mPw3>)PQth-7H`i$<-eYzy5qI0%lm7F~ z2sPk1v4Be#WkHNU41Y_#dKG@bz>-CLt3{4%np5mCB=cg18BSS!ee#9fy@?3{!+d$Z zqiyjV;0)PXU_aL@zI2VoO~bwKOr?r}%xOW~ znCOOHRIVCS1F|?R$}$|J)&z9uu$+}Isgrc7`aFv(?p$ce4oGIqDC z%Y5FWsVgHjHYeF#q;V(sI#-#&E64m`L2PHV~4Pb9`O=j9$6aP)UaDejV+xDYsM6fJ=k1754MA;|$?7 z+s6YP@P&O_T*LhR3$lvevlehlyKTNHsLe_o6$DZtvSTTe!}5JP9$|2+u%jcmLLVT1 zl?5Y*2nEq!vOwu8`||vqEKtz5G5u2m{7V=7>&oA#0&CehIb@$pvNIJ9cQ8^vaIy_3 zWO$U7?qkG>-GF`sMBYv3WO)URa}K}HP}+Xr5R$>E53;?M4Tg|(#v1V{_Q!Uvql?Y# zu1+7Y>ab)?P(8B{fOSAJG-GvvasDVzo>hFh)KK_ir)#GFg2ch zjtpU?m1uaIt?`~&PN%yB_J<$bkmIv^*Z|xdFYyk5_su9m`vhW)5~T5Lgqzu&fNgmA ze)M@Wa?j{{LcfcENP6u^TxTG82(Ns08B-;NDra0_j7ir}SrZFtokBnESWa>75v1kC z%>_mRj?bh6P+Jq?n$b)$dXU8tZgB^^r4-MJlxAfFF+7BC{Z&w|h6(JEPR8Mc>h5&~ zxUW`6t>$Vnsrb`^bGd!l;|Q3lo*%3ZPpGT_Q!|ecBt4Y4m1eD^+Lyn-) zi)j&BLQ~GyJYfA5>iZeKEsa0`0Q6s-JhJ~UsQ*)Cthpiyqkl@*p0J!G%|Z>R#VUjm zbqr7lTUq!PHPRH6#wk?lkc`C8*tqOnf}UjW#7SaTfAcrs4n2C&9yqO`;}#l^ z;F8~gS`UFBkG@H`4YBgdLsy;Rqgzj17`d?x`$6PInV9L-9T=B!{F)NawU|coJm8qj zf$;T}u|qunSTk|YbaDfBY`HRI@7gvz-a=W# z1boH0^aLUhV`%Eu&!inAFphvSt2PjuDi52Av^|u-vOq$?=-YC`Z_UR;OA_&@lowNuL{;L#{1B=6E_{o-GX7AOOwJI@5DmZq02bgA=M6I1Yw4xIElJ#OT3m; z<&cH!*cyKyYh$h=Q=v+o*hz}Zh_yj~f$Ok#6PTVsZw~wAYp52#QSED=u^7u(9W~|b zrN51N3(8`*(M@7=+-$y$YJ=76-v&)srLVUw=|w!z#c~Zp_MmnYE*Lz!x!3a%I4Luz zd(-Ts8TH++SnP=L6EwNG1B>I;Ef1d*qeT94W=lmNKw(=>UX^+AK_#2UfEpfw;(aD+VDzv8!nPey3M=~@W^gdWWuHFSA;ksDYUIc#>%G_CC2m&_2yPeiW^i9rXPDxLQ zKz8w32&p*P&=(MKBO%6mAa832unmU7U7e2s+)})_O>`V^yI4S70a|Zg(i$NlMkdXoMn7eX*My_#U~;MW zOQI2z7=oCg8=eMr;dw4Lc%<*}?jmVpPcc*i^OL11j_7&vAEf9x$S?#CaDU}K$LVV! zaOxm2OnnW!4|GL{!o&=5_9OT^^nmSWOVJkqS@-eeZRZ1{Q=k< zDTuLDGaY6_CGjLA0-W8rZA~TahPT6rfrz@RhT27GppG&oh(Z5L{7DOMX&?@1Oawcf zVKp}SI?(Q^Fn}6jjo~FAx=LdvylU@BB%=%ENffa&K8L|6fqIS}swnFysUj5=NYfzZ zaUMsK(n_UXJE;HG_eE&pv`l{d5L=QlYz`V>Xa)n>M!l$^*IJX>AqX{m4P|4*J~(&I zP#If#ipH{0Fe52Lg-NN{0KtjCj@xmkJuk@=)3C_2*mOkPN`#TgG-*eH0UbZlG-NWp zZNJk{o$<+{u)ePX##!_z53(-j)O}&Le}#2ar}t4=R7^e_a3GB1HEqJqxkWFjwvg~u zZpx$AXsJb;1tuLytmdubNZ6<18@=b5KW?I>Z}4V;RvCRsoMj?f7K+*4Ran$G2C_`IGA(v;Dl?=DW~mZja>QqzB?6e2{` zFoFncZH>*Ob8vr8qvLAZd7Yj+ewd)2@c?}<7)7}W2!MBFo<&^Wa!WC+skgFk)Pe?z z8^eYaNLH|K42elE26yG`ev~y|T#E1_tslI(OYq~l=toiIPyCZh#rt+f%sgmsn4oVD zAzVTyhtc;CY8*)H!iq>AA_ZZ`^l5Wd)7bAA{-z<;nf$99{9H2%fmG+p^(wg;ITuw< zB&Tz$(KE4=OiS!1Ql8~USX7#)l0KoaXJfryKs`%#_TBP!c;+hKlCxq1)3nV;vDE_{MARwqfJTAGZARR=#)<6ri zG?s6myag4(2vNsX(c?|2qRC6mMe_K*8GfpXhqt-ui>Pz!D^UP~-wD{2r;qJpQ(M=D z_sh|it`CqMw(d}Dw-R(@ipdRN_!yOr(G6laC6y8?qx|?_Y#@mt4J?QvgM+=2LD+y7 zGDnrFdONltE)*3cRRkHTu~v9r07`HqK|a+;GcM^o*4q&ZYSr!5(ykkh?Xa7o0F^1` zzyQ57f4m%{gR-^)=dA_)Qf#AiN6c9gJO%3SUjfJM`YRy0s2WUCntn`DYaoP@q^}|- zk%3Wxs=q9squ8AX=S?|h(^?8r^PMKpi(N5n4 zRA>Id&+Pnhg&TD4z7Z$ag+fDIxzF@^?t$aN+ytyFKvHp+hmKN@b$i-#gp@~gFhSin z`6-XE^9^vdli?R9d01U!rDhiTiH;McP*#Zu=LXwy8xjd~m`!BaSB4b`9VPxMaH?ox z!%M7xnG4rj3Ny>r&nGV0c^#IqSi06F8d;r-K8Ddy*@!HpxrV{#r=Te-a*Do0PG~xe zw+Fy@X7xcji9Z^%;u0Qbt+cP{AoHMbCM`OGEYPIwTj|y5kBs~b2?*b;GsgB#;ODYN zo>0Gtn59Q@=ZA`e)R-yC!5Kn!`Y8|?(S!`Wrw$SN zo9tz&$Yh!cX4ECRD_#cex0ebdN_(Vh$Ry2Xd$}HXCc~!UH4o?W&w*gGc)R6L+tv{a z&SfKKW@C4IpUL_M7WHIerPt6{d&M5nC$&M+cAv6sMlYEeEB**S8Yc>L!74v{uO0(| z!DPtJUJT3-yf{|2-!Br{TJw-h1Q*|I`wmMTT8hefCxd#1;9BT|O4(4aR$4wF5ecJ2+T3*VDbvdyg+%lntUwYRU!>SI?h&6@Q&ld> zN|WEc*89u(plt@SW901y5^Lmb1meJeUxnuZS7S`H`r)U5WUDDW&{X0EPVD%d)5o=P zbwJs(TiIFrnDbNK`{_zr6yZ}|TA=c+sQCqplw_VcUvT?tOZX~d`$uofaqu7)Bqtt1TI1gL2&Qnfe zmg$%DYYZC+4TikNjNX|zaFRyqh^Bi-vgKWdptuQOWy9c+MSEcQcS~XDXdba#!7#tx z!Eb|8z?hFYtley0W2Rj2X6vFk>5+s!Q>H+Xvbnt7Y7bbvXl7n%1R9JqcMkkDev|^G>i9$>F2$x7_D1-yDub z14iEqbf|htAM7SQ*vQd}dwNP=aXB+KE-T=RCE>BS`tfOXtt(wg{k5%yr zqA4>E_QQu)JTNXKU#I`R(CI=pmZj?(&#YxXpWcD)W7 zb<%#js{J%vLlrQ^A^$+h7~25ZhD-W3Y5!#yvIPB@9sg5Hh@`>9 z+kf<2wn%1ey}v5X>M!FF!TS5IFfs0X%gM=-hAkTV+e2NWlyov~530GLi zRN1=ZDVBX4Kl}XnK+DYMdx9)JuovlD0cOew-?Q8=Y>4Z2 z{{_3_7i3%DF5gG&D>m^<18^j=?GR|LB&9(+f4{}Wnw2(Zf%?(+U=d{S?JUStH6rfd zhDN8>)v{>GE;Zw%U3-O$Q#t>o#HY((o!(WeO{$72LD$&8YM^puv#eX76|D}+@z!U!i!ZG?DvyRBq1|QXq!KcMG#eMKN7yWU#Jvi3!lKI6=Io@0oPV7?p>9E7a{y=zfkI-2aoFf74n3yKRTt(5qyvf~ z4_mi<9LdhtIrdb}eWY@2Hn|!eRVqI?y#Y+RxJ+w61k5>n6X7r!GP&RruGAhfTAP=C z@MsbDH0dzozE|4G-ft`WaH>q4qP@D>NFr3`a=Atv1{j=#ZZ;{LsQBGGP+{#m4|XaA zf9J7eHPoi+f7R~XrLWTL6@Q|0SX;M@GgOgwexa2;(Yire%nCX5jDWq9OyB?gQCM9I zLypc^mO#W4GT2OZ?v65BpJ#~S2ftBL7Gc5&kLZ(YYcJb4V<`BPdlpp49dY29YRXm5GLmRz&iYtMvwIOV7syi z6FjdMpG~{mX;sta51ydeyHvHqO~?`mpF|z_L}DBhK}6{XDwG&hAXK=FB8&7IRFEq_ zg(=pIDKYU2bsXJ5#bwE; z9V>dY^33ASofM)!{9`YwvE|G;37!*m^y)P)4bs==DnOH!6K-JtD&=0~Q6&n#PDUxe z^Wi3<^<6h8PA0D~B>f6La;OUVdK=8$U~VyBEMpwDw6PA z?JQDD(^gelqQCGU*$`yWu{cdrp23bUe~$C3V1~|WBNEN3E3$57YT8F}r7WVHzwlu) zmz7`mwU)N#B1WFF8>+Tp2PIP%Yq?6TTBjXUXcL)tf$7|LV$PnI{YYAAR_yo7=9wh1 z(yx8P#;9sRC*MTex)EoCEX51H=En#K4bdJbue~9IjzOmWE+##O;&O~VSRKP4J^pTD z1UAciB5;s##C6QRK5`#45LyL8fK$17eE5!1t0mUKYF2LBzEgvz8@r@s1A{8}XL#8> ztCP726T_SfQcgg1!@9r`eRTGl`^Z`ztSF%#S1Dkmg$>wO2$Q0urJjRPR@YMUrG;?Bhrx*FTLW zfq7<*pBnCP1ekGQa0NMpvPF%02;Xrrz}<-sV|%JagZjVs`{CS|D(Cw9G+>@iUl3ROzag$*YxOUPTgtBLA^SiE zqLv5_V7aAFTIZxoWw!NXK=;JbF)N7=^CVW*rp=lZrkvk>O!o^-BvJcpMr*iiuCir_ ztnPDVtj!&9b00irUv&XcmZD0c_^G}VXRVP~Z6O>oB;q%;zOW+WZ6&<#g7 zZYD8^*ug@u4>}`2gmwhnbO1+n^gP(W3?8YqV4j&Y3vt`KTITFfei~F`KaDNQA**=nSGC%p14VeQf!SB&pU!R6Lg4d zU7p%Bo|K;g8+>3B6?b9=GjU0-u0;E4$Xc(+ufog~ds6A=w_;;rd!UnlSZ&o{txS1p z1wZp+L|BAKKciwRAb^X7En-W6L?09c0`6L_m#7FBnb>MK6Afc9BtYI|FeQ{Rz8gH4 zQ}y@kX=#vgTtco<*%{T^Zy;%Bu}h0b;Jct%3u7A%zw%%6tajFROspGDWmc){Xet`I zd2q%don6}=84#f0qTJYbbeH;m`ak?8f;j+@iv|7rnB40E&LLg9GrL`3KUr_h&M=zN z(}h9?na>ugdXGd1>96lh!880#VLB;c9)~5+j8po&S!MHyIWInppH4sno&!S_fun8A z(PE5NV;w9H#YX^f-6d4Gh;tbYIDDJmx}s8P^5Ag|W95X>%xJ(nXTet%p1yUmpxiMaK#1S$w zv>iorgh`T`!y1!c_tIX+om)ev^#S$QB(Ji8vt9J%^e6pNX@8&O|8T_oqtErHK=YO# z`@{RiZOBQxL~M;jRtN+Cn}1h;3e`$tUO1L7G0!QM;UrP%JTEg*%4}+IgKRDO@aU0TJ8DpEZL4Z#1uND4OgTHG*$=YM=B?N zw3lfN3IBeVF_|=tI|E1I(Q3!h92rWd*m1`$>CL@ib~K1!4VDnU$GF|RM$)K0t^cYZ z=$DlR3+SJ&v;V<_`QB-HG4>LDCs5`gSfNJa;z2SqGKNlYiZMBFZ=bj-B*3Z)dTE$GK zMJ3V>=d{I=sSF$r;xfG-!7lGhWhFs4#MZ_?In7^|k&RM+(Z+4<$FVwQMhZKyCcmlW zHu?blb(81YvlJ1&Hu&vJh7mS7PO>$RW^udU{U zf~PwmfB-9Y*dbaA%g2)xNg}_+cmoTT3j`YQh1O8hpAV^>=B{t2LI1I2BSUJr#l%`9*1I z$_kE^g1N|xeeSLe?WL*^`+@UXeM*k4l8*|LWa?>}jv;zG_ZJpuFd0-GSvFyl8p8SA z%e0}zZtqA#qN*@sc1s}paVt=WJn8AQC|fKIq{Xmv9OVhx)8pI| z^vj+0WUXK#4W0*09ghSHgvB!jl|9$bU3JYR`=2U$D*iojmyI4ohMczdgx_4_O#=)3 zT1nrs0^txu)0@R>k;NRc2rSSIR&7{)*iuJpWo)LKT7QtNM3!uPa?yW+Ye|C^&8)o% zIKqOa+2h1lAM>^~f4*`+?nQPNimwXB46iU3=a@n-3IJtxGHrbN~9Wm(Wu>?tD(B4RN@3(MM<#cHmG(8J;Y~MEJxTLa)Ry=y)Ea2Lh zwwkAt%%C?8d@wMVTcJgI^L$qV`Zg#2>Gtxl3%zWM9D>*HKup^|dq8O{RX!XC+Ck5Y zRrD@40Q7MLGd-E}&P zBn$D5Oj!eiAh!YX$N>nO z)NUV)h}WkH=)3K9M;Og?D&{Z}%(nYdqG{}8QghQA+Fu#vY!p*C_?0%#zQn^H!(jhY z8~+=lMDz`vY#rQ*=>Mcvq=K~VAJjTyvp0a2hN>^BKTQ_LfmP%7k139H!lc76Zqh|K1%fFpjB2b0Ao2dN?uJp1QJPyVa%jZMnw~EnLl_+jk4^ z%-44e78kR6S8t(*LlC{+HclV{_L&IY13SX>IS^9kjz1{`5BJ6@rNDHkF4U-61`hpn zDnMekz->|vVvQ8~Aq#hQM~hb6_y-5>@OcUxvOB7WhMjY7UH`VOjAW;=+DYb}BrbVY zmasRD>_ADn81uPN>SPu}b4`|sfD2Omb~3k|E7EEHm~d|03R1ibF=we92kB=nm59f& zUSCg9Ff}kPrX4qzz*rxPK+plN>ix7xc&_lA=)wKW)JZ-T1sEr^-Zkv3l8I;7QOh_+ zTGvQ4=#c_4bkAos{jW`I7w>}x$;zUlev@UMi+AP}n#vc8rq8^->W3*YQLKLD7NOO$ zjxMY#!^|v+%q&>Tm&1<;;U`qC*(L~brD4F{DLqx)jp%Bgl&V{ZM(=yrhcU!Oa23fX zT-2NOKE$$Xb86~Y)Ju55iv5*d>=EJH=YsSU(iU%PXVSmo9ekVzmI zhVV%b^jqWg7oWITCtJCWxrASbdtLX8`4hz*w|x$&?xk9bmnMeK*l;)=j<bUaAXiL_?mfYkDx;(T93EW?Ii$0&r=_p%~XzG zvhaw+ueVYQYU|yOCT&CqEO(JNJs!bG>Qt{nb|RgEBC&sQXdIlNzC<_JFalk#pEozxGCFpHYhe!nN_)8X@E7kO&K8>gyGp`xo!Lq?ZIge*|Cd){m8GyE1uC!1rLj^x;TD1k2y=N+AEC zBNdP_s2HW3QhdaVE!su|E)e?Mg7-nI64$EUgeYm$=jJ8Xy>=5$Q8pa1am_pyn61Kd zc`Yv-=g6WmVN2}<2FkRGw$VK_eRPmroF@u3IwFb~hTv7_S%bIW>46ta|3c znNRlV0Xh3dR@CrNxdiOU?@QKPJ=rB{=7jik0CJwlK4O!&n9rqnmr030k|Wze@zh%?>I^y-`XNkGA0uCIF@jk}LqcXjgee9O?IjATnv4AB=(P?ldrRFl>7$6wjUx4q7qh$(k@ zLSogvY#7%-XVW?J!xw3y(H^AUx^U&jq`{ejs6w9%>w5m=mv9EH*kv7IQgr5eZQQb6 z?s=ypQT2KP(RlYG@S!c>{Ki?P9#qMB6^9=h;+p@GRis- z+M-5jh{gMj?Hv^*jIKZ&A*;67c!{r^ub4xUG}$iFW77?c5f)4?;ufIHp6TZUg|ed( z)IQ`nykqkE1NhnyAZ!f&Jo;(u02dxrH`*DhADQgRg2Esp2#54D$^Dj@F^ieAdUjDC>3e><_OzAXzT9e*g>$`@XS}5wg;_fntg&Bq9ZIc6b;y z2>DJp0`20Ne>=FsDc7b+Glpl)|xv0O*pHu-f8(r zK^GZ5gH!G^J2u5;&|HA3w~C>29#i`=@t%#_P-4W%uGF!w(J@Y{)=RkObmLpIS9n`Q z_uKPDEe1gw_Ro692#Rc^h!P7ZT6YXSxqTph&2Oyi;H zlV)zA)T6?P~ISYv?kn7+C3sk~|i8UK26=fJ9k`rt(=f{TGl zA6p91+5DDVLsCDNRWc&bW2jq`^UN0?qWlV5nwZqLBv%Q42c&%K-~8PSfj1@eBZrJD zZ)rYGBm}Es7@TnsW%;1XSJ{Ff%E%ux$gk+kZTGeKzkTsvhcf>$w~qC9I?K%5z}Ug& zYeMPYCfNU2sLY;0C;a7g>G&FV7W%&z{yEDo?QG>_u4HVZZ{s9r`_CC@IR{%8bEAK@ zt23}mQ(MJt6$Z3RU15?{KZ(86WUQ= zo?ak*rRv$WCb?=xky8_T(jk5I_!08q*C;#pn1Pd|y{w$hBkR4NVLSC)dG+Xhl;Qro zHPr>aE%PSbN8(1|1%tnTIvuD^KOVZ1fG!ihgHZEYlJf-$%1siVPVG0Z;IJX3c11x# z+@))p_BPzB9;DxHh_azO9Tc0Y!NoT|Fw{>!MNa)2o?^n_!neL7^ocTiL4RMmhVWA8 zE4EV^C|33o>0@zgc>0yXOM364Bd0qJ--E`S_8xb=JNEktva@X0(%|5XVzTrp$gd&m zL_@@*_iNCoW(e#Rh3t{iZ24$8%XaxAAa*j9dH7RtnAcjWMa6HeG4+}}Z#yYBAU@Ps z#*=ie=FP_H6S4>wq(QuowFr7jX`0EYH-*{2yiaCex6^Wk{Bp^Tbz~}T(b;Kxt=73&s-+6c8lzTU6rxshYd({ zLzT<@9=h3cGH>Bm@#XI6)I=+@0VK zjk~+MHtrDIyMZ7<8+RvoaJR-GSRlC5xDD_9X1;rCX6}z$`_%b&s!r85 zS?!4(lZEs~aFLvXyLXEVPo)T|b$S=q9eD(*j(y~V)L#>7U@P86-3++&}17uY<^H&9L4GhW#D4Y6L1SEX|=DKH2uFB)o= zmQZ(wmPV5DI({Xek)jhPz3IrjFK%4&qT_SA#~&Hffpd9& z3YH2P>cFp(jQn8iIO6GZy+_5t(=emJPrYQ1DuZ81=Fe#!b^47!j~W0^|8%Ljb4wDn znukFCT09caAN8czvsKwNwqRTPyDw*^hV#(|(sRoxwC7;3+_!bvK_vefF2BK)j`5TA zD|!~KuPZ|{oQ4-434eWcAYJgMx9_AzK*;}xFj^h8apZ7HdlRBV+0NKmd&20uXSB;z zSF3GpKj6M2(G4VY>`bM_Ob+qC?ro(aw_yKU#Jfc#i+?*%hw{yq$;4zAMvnp2;E z6|PSdI%ax>NN#-fIIK1f{KqS^|r z%TGmEeIUv8A553m@7_R8!hA6tWPCg4Ascohk=Ad&>=)v$5%9f2=rBZLo1t^wGgY^} z@FzGbS1r}YylYFyI9tK zm-uTFFfOM!!5`|a#p?Nic$6X;BnkD$=^2G$|ISKMb9YeF7x z5=41M-O7&?$B*znEZ$5QW5}sti+3mp4~Q%y2FA`+2g?3dWukj4A6I|`45M-vro+Qb zT#KJ#;M6NOmFYh_cu`i5omCS&Wr>%-3M}T!I~$8ftZ0j+PIcY2sL*o8rvzl+wSP}d z+MQZ%3_?d;^uqV#Y78^_T{KKz^#?bnVh40dWgoAEqHg#1M@?Z{tAa?`MfEjyQ?~HU zNWIpl^!5-3NQ{@l3=`_Fl=&t%-QNx|UdI~Clj3c_aL~uheIs1yy>nVJ3hO~u=C85X z;U?67Bj1~Ih>}a{hk%OS?0mjBrA~YIsp!aPN4`)qr@hDs%PfnA<{W>5!J#7!S%JDO}jc^waH9 zt%3^vbet-VbOIyzVoO6Ck_NMRNpqA3`B7w1XJxWSm+4rGIa~2lEA3nC`6v^4Cfdoa zyQ);;+~e_YPBhc+85abqvdtY@wK0wEvA-q^%mrwsl??8LXpMWJ#=bGe%M-;@bEi51 zB%=NKHl*_lCmuUw0yS)dtMmdZBe20({#TPZ1<8A6T9XP+H)<1z)f>KVs8z~y91N=0 zUMeGE!G>YVlkdSd&KM~veyXxfJD#XyVaA)^8?ISlVSDdLNAAQBcijd26-d)5CK(qC zNPt$rtmNc}|JGptf8!hc|GzNB*4*^}J)FmbZc>K&HTaG}{@*B8{>L|xuC7k5sus?# zlGWE({J)3u03BZytp6F*o}Zxk+@sb@F{VgZEk#fem#6FR|t@uEyy>aM^$CFL9~mit-B^oHp2Wc!DA~X2b*if*1fi(4vxuBWqehW zQ*D(g`f5fnvR{goBUA1R4GMw5d1`TxRONX(NO)(64RLv+?65OWBbW-r*J>#^uMeqC z;1PeW+GjIIX;pizV6^8{fO3U8w3zqze;)Fkgm<%0qqX?2mfRPav8;4%UbJjsSC!no z)J^<8Q%0BHAc{#qxq{r`@I*1x#XAtU@S(KfzcBEc#r~nP#=Twe5KbJ0Cz~|(g)e+0Kf4sDd>}) zr0f)`AY0tc_F=c3<&}DheilvE_=L{`lOBY<+Iqx47&PR%d2Thkar|gZ5mV_kSI!9sVYTLgQCeE}Eg!p&fB1+K=oaY`sFYu%9YwYUh=z^lZR=As|r`-jVSSlM{bANZyMA zfeyoQk}zQvCvRKhMp){V*aLrfmukJATa>Pb$_jTps)ia@OeP+fIyu*wTL(- zRTBA8(W6N@4*5RA@O|$`zWq$OIl1+}7>2(?;*p8+-3~Z72dq=5M7J`xOGrkJas-Gu!Nns*bT{z9S+nN7(!MjQTa4@_WM66>-lI>!KGr9S#w) z0u@f6NKtd<+7Olx2FIqg6FfAD^#R8}q5y>5%qC5M^krbbIfxQ%i*Lz2wBkOQcW199 z6itxi&%3unxgQpCvB^chg%4Y~0N%q%iV^`?Cif3%Qqg`K!26jrtj;v5W73|VM%JVh zWz^v5XG*`@pFz}66}A`v6oFGmL0Mvjr!2$*F~ql}{T{QuT)ohDRO8A+nu$_5quHmZX_ECu^HO(YbpJ$xFoArZ7O?|8H`tg5 zKLl}b$cnmmDv`L5 zKS(YX8@sUNsxT@$H%%CoAFk&XS%=j+YbO*l$7Pe8eyv4%awL2oxZsk6g8Y*~56xhO zjYrnGIBW$XD3L5;H!VVs7x$HmE}`!wYZv*`&<3QxOL`J(s2ktXd(73#Hqu_)1fA~n zv<8!g(T%6o^&Cy4p{W1UQS-aTRUk!+y~Y~;{Z=Z1o$vmCkv#qfKJY^5toSQ@MX&Jj z|DVD4nh-l%yxu4lZvO>j7`Q_lcMq)`08cw^ZK zw}UtpYbs7f#%ea&`bf_sTJ*>$jRkgC?eh@cVoN=x7w@01*jI3%Rr=I3>O62pbjO)g zXGBMUuuiGeG77ygrgGTy#YZ#aGqErNGF+5=A}8r6Y!549@k?ObOf&rIiu;~uz$<{K z)u=EB5pQ!@-Ihjti zcPO4uyxr4`e6E^bJU>nH;d{mC5&>vgEigz#LCF0s;gwWvT!Zw*4yU2LieXLpk7|3V zm)v>N-=@E${iOW{{cTgDcI2QI%3#5}s_y6irEc*bY5b#|J-R$@>@KmG(Nu;zgTyHF<2Aniy~X`k?_f~*$>)8Yt$*qA05))+SE6$zBM-8+B7>3+S(vQi7(vXMTsx|eF)BR zx4X(nz#!7UaDyLu4o}WFLFLxOyA+u35bqs4hFM@vzYCe%>_!{EATq(dh6=;>Wy|IG zg99j;nPj`zezeB~tmrSJ+#Bq}G+VZB43=$q_~rDVb~LR^A04m|?F^QIaNjyP{;+(3 zxwr=}JY7$gIUv-p=P zSF2V<2~G-7iBTHb8rt>`1aS|g4B8e7S9f72G_4>0EK?tg@^z&>g96R#e9sZ8Y=9PIH>OpW>E4d)oQ)K)yh5?nbG(5t`b;{`;udNhodv;rlu?s z91$X>Wk{f9s5L8Z$P-=I#!x+!q7}Px>4Up{HFhW|>V$GX^$#0-uc|B(QHTqN_KKn0 ztFZ=!1mh-8&-u#`Npu^dge%vuAU>$DCWn~d9w~`_L&U>HD>iz7pv;;Y z;({AnZ2S)KgR=7%#1AUY&TsWHwSe6cDAX#>9}y!|oeA?u6|pg?XK>W^{-}eCR9Le@ zK7+14qFAb8Y3zH~>wDL)9{p(lR@H9HrxBV><>V;3*52L%AO*sb0OK?^Lcm7A99Ugi zl@y37qbmXv1LK1mA`2t|q>?Zd028$h8&FP0R}3}{AXR{=f>XgDG~i$&h!Hpl29W>< zlRyH%LC7}Mu$-zO@CtAzbCEPFqKW_v06zk_z_T){I6wse7i3mmHK^bXa8yQD3g!w< zh2R3{WK>asOn@*Mlq6hgI(bzFU?m_+1cnTdl!;EnrJ|EnjV&MqIsh7z8bS*20F?k6 zDqy*ct|ZJBtO;odFW>@X$-trjl~guNK$;{FHjoAaVh0u{f>40PU=Tg9I0-}qEQWyi zfL4hhB%l=-L=Ch`0^tL#ARunwZXyT+xC;g`19y`^WWZerNC|G!T<&` zFiC)c1gsxmAP=Jg7>L0N0S2-#3xI(X>>t2D5rzja5QU`x41h2VfPo}z4q%`F;{q6n z!x{kwaxfq8JOo4vTu1^50v8}41Rzf$h!V&H2H^mCl0Y0lPNdycF&GnIRTfqWSe1e~ z09F-Y$ADE)7%5;C2+IOEe6c|QdM1GgfSwQ#5AY@tgb5@DF3Z3=0IPB^f556V>6bvT=o+iPCfTs{RCiqzt_5t880*e6n%fO@o{t~c3fWJJ<5PS`WBLj01 z;dH&?pg(2s8r2sendFa6F(91kMFqPlTfb*THZm z;Cd3A6u1t73j&2-n=U|MFq{(jLcPBZc#?oA0iNVxlYl2N7z^MjqTnSF&H(HJ!-;`i zNpODP>;D>opXFfWfG1H{4xqc~m&)sblLAY;n*6JYy_)Q+Nr9zQ$$;K~{a0&|aZO5A zQWXL^g8u;U64gb(5dchJ7yu7E8&<#!aHlF|0Itd$NU3^)TOsNas#w5&03KvEw15n7 z1t_HfcE}t^syZDjT?(T;`H-W?8sqHw51R|%NCg?niVFX?n`yc7hl@J;*9i3$o}$L+ ztSc=<9Ne=StQ#$ix_5|~uI4|>{3h1lOOQa=oC+zk!G>4@E1Ye4apSzjYs1!zGmZFN zH+t#=g{?gb`;v`+0ZsjPZhM%Zx|-5TALDiBl~0Mo>Y+Q|GpQ+hq@4T#8@-obyI8_` zskj$CnqAyyW0Nz_jI&t?@r?foyFV6AcjE8Iw~XSySS%tF9wz=0-~5?I{E0b3R9)MB>;cs`PjIOE}ts9gC^zZ zmR^;dM63P|Ns+?1^;RHZs|2|*Jcny3BFhIYxr(6;R3C8#sI6I&NF>Vic=dw!Vd#+P zg7v$aft3&rM4E;>%JRE^$&U;7W;mt4ArtblN+GVw#xYu^2z)GrQKjRX)@Z_&n;!%8 z9lZGZZ1gMFtU(sMA!Tk{US?}PPPkTr0;sg-ngukq!6ADNJj&@3k89yAd0$5QjvZpc zio^AE-^r9l7~th^<}T3MmCBkL#HQI+_8eLAo1_|gUM34x@3<+KYcCRD=+fY8dq=OE z{2RkLR~smnrr7*A(*7|*v`m$3>t~JAH${vLE{BoX^TD~X%5PPU&)XTxW&2$2g9=%C zYHokv&?3bgEiJBQB!Q-pG$M(|A)kaJ)Us5~-s`1(Q{aQaFsr{~|#=zWK9Ja{H1_W5{vN%pqv(>l&Y%u;DCBjfT_ z6-iKfs`zp=Oe>UGsWZ1))^D+K5{*p1N?9r*yRb;D+#JS;FSWSlZ~gZqJFpsXEePo_ zTZ6RouizxqL+q<_=3V83HBXWTnkEADYBRH%PH#Z{(lL(nrUMGD;)2=svH^9Grn1Ku z(HZY)9_~T{oceeT4l#-PdAYD7r_;h8H_}V5d)PArKf5O8)gKO+3BlIJ@qLJiuxS$O z@u7zqSlqflgOkbSh71w|RB>0gB&`n1ZxjR{j6)!Fg=;E{}fRmaOv+c{4f67w|U4bCSgGa$V<_xt=0 zrxMlkr+ZW!Nvfo%3PYlDu&Z(8oZjVqSxA}pw2I0~7)AezIe~54<&@TWBYrwn>?~!i=(qBi0<7zVE)zXLF=|-@)(*`V6xDGD}#*%w4)=v`TdP z7*Qaw9$eJ<(LH+)^3v2F`{BiRDzoXzvkOKn{*YfoiomNGp>d8= zD-t982cN?y>u%n-8beR4{}4k0GP#-L$jWY;ga#`htB4Cnutj2J|Mj`-;V-yt*kc(F z`9tWH;kqj*=(_eT)f~~l$DVQyVItuMTh2S`IvE9=@Apl^+>nCIaX|WCCtFl1J-T0& zTzd&BI?C&ofpt9byWcy|)!J#@bGqhN_I4=&uB_whMCX*^aP8s8rcZbaJtCYzWtk)> zVP=MIXh#<1jeQ(AaVJ%+OoXV3e2bEiJg?(*roGf`4H!3mTBe0oQl=$=_7*E4PhZS*0LMHb!4DWf2K$^r3t%UHc;I2ijGEDa?ZI z&Q|~KsxbU|Lo9!0tf3Ju&89AqN8TvKByLq{mK-}RdZ$db_1(oPS^!H&mDHW%(rz__ zZRRre1JO}Z0@haxuOfa0iukjLlF)0&J~ke~%5*vfeIIUKC1QtRXdqtP--~Gt40;h< zwH+{?AeYAbEO#t?!j>`c%jk4B!t=2RRxwJs|DD`4Af-L2 zp&=*nFWdDpHb{7pm2I3oo!kk{j~(X%sr;#S$5}i%Gu2u!a#WK9fzL|nS+~7>CqgSf z@luzq>dpqR|0YwaoN%PAU*tEXfuEsKeb?Lfh8fvg(-^K_YcpR0={l&EaLJFN>DJP! zKMTeO;vpFrRa}4Hh?V(ek*&iTfs!F7o!FBu-#qV}jM)~MmU-$DAtw+f^sLXi z?1I~j9ijC~m+yKd$2 z6BaNFma3l2snLKqkhfA+Gc~Y_r7m=a5ZYVq%(H|}D9ATq#ibn_{Cdl6scK+xj}TE* zJa)QHp4TV4A_lyZy`F?e64Z|O_3b;d?yiV^EgASTRbf*<7z@RU#6*~4gUv7p)1p{( zu3K^9#&V!LFjcxgTaQJ6c~-JKLeBN}Dy6Z{C*BMOm*i>tm5CRbxan1VZD+^L3BtR) zdyr=-dAD~z_D%E0PBKnOZrK!8w{r)NcJoNh@siDHXk|swW!np>HSKrTNn@@XyN>fNzD;rFvCv3JUb%69u1zQGc}G zt$4s@hV}V3xkcS#w>ZcOFU+($1%UM$tsu7o3MSMaLN`-5J^#8J;@P4(V}cVhBnRVz z0p!r~IbL0dWSoSg$uybOcL7^ZAug>0#2F;EBJ|c9=WeJJGTd}m*a0?$o?NqRvm#p> zrmh<1ibTbCaaxSQT-$xDN(0BRU!4p06v6X^fuz0FE6e@4vuf7dO^;!{-6g|mt`P4i z*XZuz?2pCV&0(nvuHa5T3iRGD<7o-Y%tbn270Q{%d@flUzFydELULPa) z`O#L^b>R3XFzzD9@UdxLB$i;gfo^Wbx)WQWLxe_Q269152+0&w@+N#gu za*KzR?HUrLsdz27HYa$iB;qElbMJiEvQ0dd8(PKTnd{H`dRL@Zu&nN;pMWUl5a75y zhJKE3oXT)2v}LBIVWz;#?XM9;B0eiBf63z``mHx%Fcy}aXet~)75?7tc;MSXJ(Xd~ zOyZY&$8}fN+b`vt+@OxQn0l;Dpq*ltS&5`CONl<3)&KqlLa%!&)tg6LA1{ItxhV!xy!zE_G$ilRcDNn`{A4Xl zHW=Zif8ub@RF50N{EARiD$~OH%9m@*<4`7d7cw%e)9CBWg|agzY>dQC9RDP$vq~7n z!J;?GT~tphX3B5VkS6Yzm&YsVdjTwkP3$fTF1So+ z8-)jO08b^axBlmT+&206Wt zEl4sE@OfTG%%iVz+Sx>t7f)RcP?R$*u-z1A{1f`7*=*}m(mfS)_nhmQviiaslvB`T zZp*zOyht|pR$kU7V969E>~R8T`CZz`LWqM=fP99@KMz;4SR&;=5#|kV=(aADKR}&wUwjy|F%+?V&|-qsH+Jpd`Oz zz-CXFQNNvYABS6_Dez^x+v+x&sAhb&PTU-_)f?TnG?26HDySy33pHt&P@WO!?Ozyg zt;xk(CUYWj51z73z9t+qLfA2wJ-)}$)Lj1sO{HI54_Yb9S1Wnbv9tJAJcchUG6@J( z*!+Wri((qCDec|0u);gOj*?g{RPzpHemg-|%eYhdMM_YX3Adr&&R}ysZv5W~kB^Fe zI6sDOpYLpb zxBZbWFQpza&u2~eb}KUM{PHb%V6&k)nc4s~PsK+Gx`%#;VJpkC(sy$((=mav{Mo|K zj+*qkM0>ZNovEUyG@PQ&4;*47#%e6jH8w6ml}toOGL6l#j9)e2>!nX>O@x0wZOoi5x1E93Yx@t+3@#W>r5a}D+2^4= z!ctYx-2O*OmRs?IyMWileo=Gq$5e|}XtjC-q5GWtxzY{i7P~CbnfAl(uWw z^)U8(U#KH5R>W6UizMsHQlwDeqqEb-hD+R>5jr5?gx~~o%b-I zUSq?0>8DPQDpuL9l`p;HMX3<*Q?B$dcz|+Stpt^L1f$oO`2dqjxX>rNZ)87S8|q$F zi03wFtcSoTdPtRQ(|DQUuJEieZ*pI+k%y7Pv}^mDMJw!eQ;v^Wx`>7~QLBsVuN8s> zbh$tBE$7@*UjUu%)(4e;CRx8_u)@)cJ5{38v8RWz+^$V0JgtnCH*4o^?>IT;@sZDo z(TT&P7IaUhY}s|qO^?!WtlA$E1D0<+8he2Q3!wz!|YpE~h^Ys>zXO0s)`rPBNy!J6&R?LLIUXIqfnYBI< zKE}N#*(hcq_qa2DnP|k51eZL7Gt&X>P_}!YV16qRS0z@eNU68t)Fw|qkoen{SJN1$ z{m?I`Z8lSe6o1H!AeRO0|CLNY$UjdplZvf3k&--~m)u9rGGGE06}QT~j`1PYC(M5Q zWYi9UQ`k9{coa5sotUf(?>(+P533Yc_8$-*ZJWw!Xj5@FE+yo#fc5eAwbaN41u_{v z-39hAsFEvn>1JR5N|A8T>zLNj!|mXExOg_Ex)IY4HDhl$Bpm%xpn}y7i`Fa zUh?0J5+3^V`fM^K~g| z*vD_@^DFnGXBlw)l*BUA9b?iT{d+QRefgfSNuu-U4_6H=Q7B+vjZ4QV2q2*7f zHYHm&dvMp!JQJp=Z%MhN;!C)GehH^uxq^>&REB+Tnl6hQpto3j))-K2p^wFUOaUm4 zgSE+wQsx1E-al{aptPU3{;*tE6?uNq#mNqNW{IY-<+l7jt$R`6i7a8KVtVdPQbyx~!m{~&a7x?BTKEJ4 zuM^z2AZ*e2yOz^lLbuIBrD*$D$iVczNpdr$8aF0*=F|?_Sp8^Gye^QhB*@pbN=U{g z9yG$z9G=siuDU6QCn%NDcZ}iFoJOP)oY4AwYpSlxldW8T&_w92HY~ST*}N03mh{lc z*xdLI+Al+M70v(Y-za)Z-7ZhxIOf()={%U&%)1+~nbADE^P61Or`)niXs-t0*gb4#rXTeqClr!p#z~GG!(>{3hRC z7T#sGWy#eQr@X~RO;)tb?t5|D^9d?m|A3F9Nz_GAle@>{uZtnc1M|tJ_Nf(jnr_X& zu3X6;6gJ$jvz4b3>$v10y^KX zP|1udem|E-z$G%20DaC|$!=ePt1^R4_*9NhNzSU`(!b)eMgz>^-pt(JallH3>5?kw2D#7IYRfFECC=qT^K{JlLK*3*_)JNIou<_% zuC-_Gv&_HH*nOoaUk7VEl2dWO{GKtEzVvF`R=<~@N)tlqIvCm zXXpI)d^&0BGDd(zqY}sQkk-;YID$&1=PGL@@$LTIkR$ZUtB8WoposQmU0dk496AG;&C z+pshVjl_*RUn%oGp*wQTFcZ1d#UG|Ux0uxhjLu}8gekKSscMnfwNT34Y3>)lL!9W7 z>3_kRX4oe;Qbf12T$sob-hmXcpKIVcA=Xckee|#x+J6R#9lskip?xI6-+SV2GvApP zyB>~Nd(%?)7BSRNPc&@g`#x$C8wvMf#5Rj;;dO2<77?A0+1ddG7x-;GvIh8x-1dHA zvH!87xT24z777NcH_|*KSDdq#DkcB4oBn2#@j;JID$GI8xyQYyQw+)k7|JYW!fot; zoX+51DTSBPX_M{`P#t!Pb!Ipw@nEw*>X}m(p{X8exZ_h1k*IvFac*5YibZDZKL)U%QjfZ>I$*LZa$aH?ykZS z$q0$3W=knhTJ;Qag?Y0_$vH6&ynFud)V_Xa*nm;9e#{NS6F~ zdXP3$;9lFG#Ahen&F)a(f)XCd=XByXl;E1K>Eg3JNZV-uqHtPH&KRDX5xm#}_3fGE zG#O7p6BcMhcKNh(kEb!GFeTU!?!MgVMUj5jB^kDJDG25P)4Kr%Ib?=2aI`DPo{T$S zP^Dy}AKG!#A5zZ~!bg?2EFLo-*q@PYKhw8W6f(_Axy`W)->vWSk0e>lb|rV$Fx#D1 zF_+)`Xe6qZCz8r{l_ux(fqNy~L+_moa<->2r}Kzp|COkGss8Q_aUuSo-Vl%`-6_|p zXG&Rj->z@Eg?~0t%ZSemZ8o|h9L^Z^)0_nf%^$IFP|$Js=qCj5rdY1WUnwonY*G71 zOLwZRZ6tL;x~_+eRL(fw`O^zBB?t{cm1c_Nj;4~EEd0S_TtZ)<-F@kUd%pz3a`92aaGyie zZ6|mCJZYl>rL#Th(ql5oq^^Opua9K{r4?f=?Uk;1JA!qLC)c#74SijftmQXv%I5o9 zJNuyIl`L1Z2FX>k?{eF4j#ZMU7aFFz*_{%R3g;|>KiQzX96-#SXys3vMok~DK4#3Y zSp!EzY zh8?e>U0kq|)7f4?2iA3AQskY#=jTG0%+r^i$faNLgEQiSK9EN$`_57<-1Co=Ku5zf z>GlTm#RT5Wt2bjcrAUruK^dh?Gbt8>zR7E{d41u$cVtUY7O3wB(6c{OdRPslyPKFM z-!o=+L3C(qAKl<2mPE9N=q&e!G_>|p_xyE<4$Fc&$d!q&LEuQ``5oSz-W3jr)Pc1u z!215NkU12>Al&)AN&&Q^z$$`i}b4M>peR-PHDx^&!T*u zs&iK!&i59bsmu0j%6-Z@QmY3*vM2K=+=PHKvit*yhi`Ei*ZZ>pNC4GPaKrBrI@CL@ z0jQ+86)jj=Snc!o?6y$Sw*vP%pcX3%Y9|ESM1k1k=OwSzi$5jt_daHDoa@P}_L^ z*Kx?>ffS9YyjAj{Z48Q*JHS&xy*4|Q^WJ)qq251AK`=UR9DcTl43#z;>-q`0MM+Q% zFH@ntzqjyVYy-JMxkCiXiiS+2{fnlKVAfnpqQL0Zh8e=PPI>Gw4=%Y zaQg&CP%H|izp3aPswk=`UeOlQ75gT0OwT9RC)W#(d>d&Y>xbg{B%_uXbtZ^4o9B-Zu}8|JF4HR_DkN`ozKxVVC7=LmBUSNOY<)HSqx zlckgMS_9&wy?>THBco&&Y|x=(7j1k-@lZQsMEs9G)fguO8|H3Eq8R3HSd=Ad$@rv% zEbMji(0V~I)+zR#aN8AbI^=fOpd0>tk3j{PbhnWq33Q8c-88sddi;zSe9>$k62F^ z>PA~qWXznEDczj}y7WV_r7M9NzePl))0Sv{#oiPpb*iNhmqadNP{moGUrQ-C0fU(K zOl?Z$h6{rG#pWAO6h(J$hZV6BS7J|JJHbZ`Izao9P?qsMHJd06bF7v=YV!!wj*Y{wK5bTBVmmtIZSG3AVU5}PyW}Jj z4!D8S)}A|=35iy9Yo7>+*6DXX4=9ctzPWVII78RVetAD84W(mI`l~ecqYB>0$n=(M za}Qno@1>O%Bgwi(@fX|42hoYn1>EUtncMVZixvJkoT$?D^AydbmT6I#{xQ4s8!_QB zsFrqChx)0rR$XX)Se^eu#(MJYSV@;xV^AYm&n_b=&E1i?#k=*~G5uEY9Mb;wBtj#h z2>NXZ^=4aG59;N+iJ+M!VZYt)#aQ6$|rx3WB%ap%H*FM zMrrVW{93Eh%O@c>iL`zbWmx=K=(wlAVG2-WoF7(J<78sxfYfyHvL!X=GWz-0Jayu* zcA5BsX#Fo$r6}v+;&ffhi%yAD$SQj~)(zgL5{@T6&osg-ok?EYX#fCq9uAGi3HVj-b*^ z`$dmZ23cV_GW(aZv}yM~;TncxuY|s+fsCMZI=w&c92LQ~E8*@P@5B0u{aIYJ;@93_ zcN7EZtleZzYH|fV#ufKD5U*v*&P7TyjBp~e^{r1-Y*uV1Lpz6GL))}9s(>al2xhC zOVjbSq?Jf&w?CXdxEt)&W zc1;eodH(M4A7G=@#9Br^q86lG^akj!(YX7N6Km0S ztw0ew^)b_WcY&(~F@#Qe#FO3q9HYp=%=?pjWR(MB4s*-soI^#f{`!CbNL$-bW!8fK zurI0eZ!aBKJEgR@Yk(?lNo6kYjuK#-~5pmn3Ap=e))aR$Ex! z39CcLnwkxn?kpL~prG$En2dpuqz$8fgbO~?mmesD^rc)2zhbiISBUN_=?lE0q0R5) zUo3DqN<^xS8$ z?1;6KB<{K&qAwxvH@+%9$sP0^zYTvFS~)Y`(s`-yR>s%E`)YzTPlX=gN^AH_!V(cb-6X+;P4>jZ{|kv4Pq_%wdcR zFIOT?%R99SA~dF-iKH{ zd?tFHNhd35Q3r;rd@4!lAA8C%g(+2S+LBRrYIl(li){RhwZz&BvKl*t_G%i2K@K=x5f-GJ9rl;|6m#A%UTH`X6gIAP|C+oGAh;KWhjxBTY z33H^mW==mGnLR(yJ%qdv(Kmm;61)AJ8CLJM$ivvzX{BMe#4p@D7LCZC_25kl7yz_zx!h)yBA8;rYkox6%69??h7s7eB%? za?giwiB}d%KAbjIbZJo1_ODjNRGN}CMCTLaTdErEq{`}Gfx09PCc|Yc1c=Ef#SoT? zvap%#St0&tlL%R)F`aFl`pW};cx_97f>{yL_^uMR>CFxEnR?!(pCD{21m!XdeFGnu zAhoSAzg|4#AKr>KYd1f>y8LoNDU3ChC8b`hG~_BVyj~P0)6~ToO-dVQ#ZiDFpB5JQd~SE8y~)tS^KDbqp}#*yraPSUNQ`PaL>lX?k7nu9Xgx;sJz z0Q*XdjZ5D)Ob_;Qk(U|yR`s4PO-{$Y%nP5ADE=L>wwokZHle1P%4}U$Se1n!Lv+uI zj$NT{KD}AFoVvR`I^NV*%Bks`nz-in-}Uw-OW83L*8O<1MNla>MFvNxF^&aa&efai zP1+ec+8LXQOwKIy#Ii+W8+>BwaZAc6%=o0TrEZu2H`deUCd^NhYOap5kgrKu_ji0M zey!y`Eq*F~{b-@tVjRrn+%S<8`QMA-^IHpnq`PhM(j2o0DE!5NmalENEGhGs14N%v z7}>6Xu2JeBjO(Jluwal<^gre5FBy_)SE;%V zwzGpFC%x#k=6gopr_f8MRKCIkE09)Ax%cv1_Ne8|h|n6BMlM!9AL(a9CCHH22uyXO z1S-VHH0zmRM4F6QL-#UvOF}T9z3{%d9!wl@{NXh-6UEpm+S%YV!3bz}WnCW=CHEDN zr0nIEIS!k6ckxX`2vagZDB3TJ=~?LA*o!V+JL)8ao77AR*&&~W3&&QjmvI*prSOa}6Jl}F~CrQi1pfBGA+ z+UVyRMD_eX>0~E-y&)W7K58?o@QdB{7{}ic4Z{=vijnM52ZT}X8If6B78=+m!Fly4 z1fzr=k(*R~2IytC`{{pcNFkU*76FnP4FCq&!hWD79b@-rpSlkhjrT51mKgL`5>bK^ z^O~4S$@T<7x6dgp1w477PD`psCPjOuWc^{^()*&7VRzB|RQ>M?tU0p~d8JcUN$Ij1 zY$g<6H*V&u(RTY++t;)8iv~`hj{G$s%Hnz-z~O zvtM+MR=dXd_1P&}Xj)D6Zag*qwr_k5_0K0FI?;JRjuQNO#jKaL8CY#gpEW}cmt-Hr z2?&>czS12@ew4DeBA^WM@Q507epV&PnVDdQoa>ABe^hjCx%2Hu;%@)H7<)bcbbI$$7IQL!# zKWdb$y=w2d)|$JjdQXjbd0@%Kxi;Sfz2jXJZW_zDG1A!l$uVj4%=gvF>a@={4GPLGXwoBPzzAP& z)H9$rrZcvO4lg^snY+FPqz9Q9m%QQBdyH$kBReh==iGRnv{4MMrPDVz*S9VmCS9dG za{72|(Qd`>uft~LzYBj;cx)~{4Eyf56=w1_IdUYh1g*81M~dy!52-wMtnOicZ0UC- z_qUR>)|WxEX_sbD2VYbBb`gL>#_fKaFCFs--;MkuaIZ-}hio!ayjgflD*aCzWX5$f zY)6jSM6EVv*%m)uGCR=9>`03N;72{awPqTHl~f;>zQdaQy%Whc)>ROKarJf5Y|1LV zxqZ{@t0^W$)^`4^+!?w~*>-BnCq=EK`aCEx&?WMKCL3Nn`yG9AQh|R(V4KP}SBiN% zVRYZQGg8Z>dWw}17kSzZ&Y{PuCT7zK6irdO_*xz{T9t2C20B`j@YjI|eujXS0~EAn z&z9fU`D)W4{<`tYyhZY*``!)Gv-j6Am$+%(hXHKh86&`|c4o#x)qXrf+iI5DT7#X; zjM=3_(vGM1)WCL+W-Lg}0@r>QC8=H?n)D9(kri%`J-CJNV?{Yuq!?PH&fJ6wMMPk5i^ty20Ale)w%ydwcq}+vy7X=OFO|r>vOH7Z#g)odO-pKQ=eezXg^$Ohk%{2Vu`( zSko-oRnU`5{0{FR^;#yqHga4>`DMjtAQm0pbLR6)D?vNq<L2hsMxFf2BB@i@B>SUg)=`-|BXfIO%}Eq;^k8akC5N|1PAPd(V?UU* zZqmFMTmQeu)vx7rf0az#R!6w5cRHpDCX3`!<}X_>TmGhGra>>?&_y!QV*^Dk(syO% zo!FjDz2vDz8>CHHg@vn$&Wb9-xmX@uHdSKrQj&Ryxt~FLV2SSUZ=xWsmm>r#Jez zHZ?jb;Nv@poPqPv`>QQBtCFUMQjUk!$vo8)%2S(Pm!j|L)Af;a zhy2C21K}=Q>a~@Km{*NcXGTG(PKhT`k0fqrhDp6T#kH&mzXU3xb8LU|m0VLu8!ZPq zr#YkBwwHB^t5%(Te0Om2y_3n32_&8Ij3u8PY`Bq8C!9DAqm7X1+06Wfs4tKI9jj zyr0;Q5bgGldJeSf7oSE50Lfy#w=<{-0=c*7YY=4vX>vSO{8=~#blUyRJA&b_pxmz< zk`U+Tk$8K*y-#8;ULg=>*&9M!Rm*$UR4AS|7d~U1TDa`t@c8kXa z1`m~f8bE*bXaD85kIJM4&~qi3mHC*)3NH5eS~}E}{u)nN|vV=T5 zoAN8%JX{4ic%!Vuw*6D$62j!qp;X#M931A}^sw}y7DvlmfmPIdqJ z|HP6(D4~%8N5~W_#5lJ&`|7JOF1x$Ymse>;EHyQ~RBg1Ei<2h0v)gB~9uCNm3W55MynN8NJM&J3Y@v6a2a6Iz`^W8%fBHO-o7kA`hZ2~tu;eSG94=S0!H&T;E~xsp_E5 z@=VYZBic>nDF*_L{4~xA40|T%nHKG)n(hecTb{)_rF&uBk>Fz6V#15Xz0b){=uE#P z+mt9GiV2_9n4nW%7~X)HN9z=BTApcSFT6MC#FW@g-)OiF7pUC9E=+`II>;%7zSgQ& zx334QMMDq9B44!VDk+yDLO*Z;WXU8UF9I2_&r^W+C>HTv5^A27(~DrJc@ge`0+zBO zmbl7dUz&o0HnJbF+UT^HG!{`Ybc@Tnb#KuF(r%z5#lFQ9dCRWu?;v{RcSu{E{OEO) zDLfybqq>dCPl~0Fn!zBMTG3zP`$+ymkxCO!Ikk3nR9#u%^B^t!_|7aU$o|NP`b})C zG7fEwy$cs``~!@WOlPa>Fom2#U2LCO6#Do&0;>is3BAf9j2+A~43Z+KN&H-&3Lk2A!ghYReG+uk{fWrEP9GllRUUP^% zP&xYFtvTs)h)tMn-Ad&Wf{KEfY67qq00iSTst&fM#S=BD%3QE*O;!G$V>i*o$xcAx zQOtDQ6rRqMV;H>8DFZYA-iVN$l(X| znuc{>bn3p0#@h#NWbf8+x7ek!3%#FN8yB`!Y^C*33`!|@>-u$L1ZYGdUYsGX@w!=` zm}WvihW4s~l~5ad>?BGSD#HD&G8I?b@C_kTLue|Msl--^criDVKyCt$X&i|m?qauq z7+Qw8F1*Yh8~fA{{yR%Uz#+5>yso3tp4P75jJ>!%D#{m3wTy9ExEYsG(^Wb+KW{_1 zva@1`33a(X9(lD+yC%!wRh-dABZsq03T$m=fC;7qNeOa@(%Q`CaPFaIQk%tuF(QEp zV7pjtW^*}PKL8xNfz+UdFzD`UP#zBVp0K6+t4vj72#J{x9>8|LyU}obZU+7%K3!rG zG=QTD0fK1O#()gA9RNg3g4$3r*$^OmW^M2Q-Mwid5qg`$!??2SBzsX%H3HFo6>oZ3|WeUSUW{?X4B^7zBQpH}C%vfmE{dir8rZhHMy+k*!~ z9Z^3(G?()yE|)VBgpk7-5pweyWP;EA(`#@}e)yULD5)UwX7|JZ|DJ1m zLO@Nn&TldcaL*(t5+zd%8A4=sj|(uh?YY)XfvUKzpBz=5-r#WsVu9auU(;B#;6r@GrA+L``x~{e|X0 zrWgS?`Hwj0dnyPn2RR0~#B6jx?Pn&)zMdP*CBZ)MN`P4~}+@fKEC^kVt`1K!s*8p^RkW^K1~EJ0l}ic>(6qOerw0nGg=Zu_rY) z|L_&3W*RqGUkVKA0V07W|Ca^!0YF18=L8N{E*99+tPKv(dRNwo%dIVJS&qYHj07I* z0V4j#&rU+_30V6u{7?WEL!o{g);py!w`!YFtYtJX3q)M&XyDaupzxowPm~&pI|(xM zs<_*PsMbY4ucEa1OJ>C9GnrUyMrRTVSQ;=`t)PQh%~sI<+}dXBxA@qcpLz1AnG{G6 zRSr>ju+yU!bYt*Mf8c|KEl~LbP%Z3~aat6k%}GS(qVu;rCuC+4l#Z5p69Pr#_=W<8 z?SAIV48nC>;GE<+(xZYnn)#6fTti^}p>5OUH^*|){U zj^fHphOcozVn`5^KlgL5W|0500yMcFS1qYmgb=T!ng$Tn+@#fF1N^1{6GNg3O)6nw%!?N6OTXb+HS&rFV_r^$)M+ERWp~q z(&D3ICkxi;V11;rF*uE5WUz7%FM|V6z*?P(VGp^}9G}~cV|;7H1h2^n@`L%!o<1TI z{6(=?-`o~ZB?ay@V?xvvhn+p3TRO3}GV+PPgBme$$A{ zDVxhV@By%ARt^Vw&$0J?ps=fkwtRrk7Qp;3lv5*!l(iua>UfYUpj@+(f-Y)X^yloC zZ7h%a4ko0zY}HfqlLreZP;iI~(*Zb?jciJ%L(JF$jF-zXnQ3xZlE79*01sn)0U$f!<3v>5#ubKRMd`{!zI4CX^#E-)m8GO`}+E>nUKbBQU z=u^fG9{T`j4uisGzL?WclDFtt=1HQ0RlWFVy6E3+t6ALhNE~hc= zzc6R%Fm`ZFDNAf2tnt!`T}1g8>97M~L5(s-7K=j6bw8!r=p}FQ5Au+VF*n%m`|1jD z+b8v-joGbM5Wqy;*VM4+@+vtBENdxk=^df&C0qotA8o$XrIcGW!jO7L!MgZP~LM=H?5HZXSBMf0EmY`vdnoY_P*d;oAOXxU~u zto0IX!SNGLlkch0M-T&tTl9OJeM(XpJ4mT#4htYyIa=7o&1T^@O#-o@f>3f`AVIMI zU_XZYgx+RlJI=l$sq8g?z>E~;Mu(moxWEGJJPB%gl{pw@{~9zH&iL`G-nIOeEC6;V zsJGek%>PN&seJ}4_hdh*!CtlitXG-f5PK#NIP}lS4y_>jQf{#P2S7tN4;jD%=I;>G zhPZZACWYtVH7Lnm4CK(Gg$#b(Nuu>JHq%Sc($8qP@g+b$+@2BSt`}R9fXyws6{pxD zTx)_w_Xb4T4NJHV#ULo7EkNy6W_qZ-ASldi)SNY4NNM~!jvKuGZ^r)UiZnlC0k+NM z6s5N^KmgzeM;vz=^%QrU$0JrZczSZAFV#6gVDD6>;l<=oeWk&ZvaQ#z!#wU zbJen)iRJy5Zi3%-D|1W;{|nL=s^pY5_ps5|{Qx-X0g{8Nku}*i$`A$sHA0qtD*uv? z(LrGXTOoz<>o#sM{|CTrh&>JH6j2k?6s;UNHuLE)4yr;0vEguj0nvd00$#ZapZnWh z9Mn|`{IRDI50Dtbm`wm1h-eFNm$0Ru;lJc#bW2&%GZ_RWw*{R2_jIl92A1v*{NX=& zKYkkls0oF7a(sIMW_eUQEU?M<1-0ZnZB^!oVgJiM-1WRmC}4~ah6s5naANm0C+H@O z@zryR(6Ut)waxt!3B-g7vTt?|4={zL_h*O}Cxm_yBu4Nr>2SXgSHa^Bgq7NSDX?kJ zH5n)f8HT@70SJ&2(v`y*$Y$X_0`OpT`l4)YY1Dd`ZxfZ-`F`-a*ayK*^yzqKNL1$Hwd#R5M&6U@KnT%Vde z2*R1w4s)SCpbKTo*4Bao=PlZv1&SWD75EW>nv(n&K>fSoxh$TxRtx8c36k|QsW$!3 z*%)ntpU134=S4VE8px~OZYAhc|D_!6cN*_RHP(uRmS@Tfb8nFGI9OjmX3PxGV1cB0 z!E16A0jN(Quj+ogHZ!XI7s>J7Op{v7HtzLB1fUPX2Ce^~`442u@wf$-XV3t>h)pg8!-Hroqs6xvQOzYAofFG=&_SLvwlla z+RD8DV0rO@d94f?NjP+-)a{vAA zKPGfI){(%gJ*g4iN}?-sr6m@0^bdNWiYd*n|4?kf0LCwTQJFa>cC;C&nHxwDVKYA> zK&wyXBg|1@1DK<*ZlK`^Lx&^JW1Dn{yPM#jG24TUF_Wo{L1%B|j|wM1 z5F16sXVA!Uf=>N=`HFzQB%6<-LO?UN8KM{-xJDFb?!#LFP2F#Fa#iQhBGW0g8&ttu@C3#75L^zJw4c}nBw4w8B?{fv* z`upj_-Awo|ZpJ9lTmcT7QR*NQA0I?a(N0ZrIjR!pZ1talP$`O_R&z6{ox z|Jqq@dHf*nNbKRpM4*KrNZ>pvzEMb8(=^fyPF+TGQ~P0+&wOpw8(4kGEXj{!&4+58 zKCx1M2XHEBp~yY)pnY}QI-38Ns~auoRNQ1N#mb>`nIaF~Qv3KswML8(Dvb?LU_PVK_wM3(!B2V*-nu znoIV-Gt$<(x=HL?L{+a2DO1X|3#Q<|lhV=N#F9Mw8${da%$#E%M7lpW`w!1?depPc z2JA<{ycdJDkzeuX-`$7(AL?HfkF5`9lH51pV!-ucDAH{FoJ=2O8cqLYy}l8 z-<>*<5xifzJb2U(RK011&;4WQAF9JgQT1x}fDM1KG=;oIg8q+VSO+F>>#?vTwl^>P zU-w~(068-ALx4?E>evXm1y?U%uS$lm`9K>lAnmYuQ=(_|fAz#aH3HTXCEG!BBVxJ- z@(~Y4d%>7s_U>z1ko!`m@i)L4eC~-0EOwelpa0Sw>#ZRTb~VRP-6$Be{~r36+|RUe z#h)^{1qv;%qy1!DTOVcRo~WuVa7l}Iv)x)v-sC^Ja;V!7UR_rrJayUg`b+V*RyArk ze?A$wu?qb?!uAi%-(0wFH0V$@vY5PSO@_JG`Vdx)5Bx2W5$}5B*U;~R?U6|KYsJw){<*;rbJ@QI{V%8-Hua3anw%W`48yZdvX6yEccSvqE z-<{}Ti8&?B|DV`6H!kxo`HAKo>o~KV2a9tx=G%bj`LJqCSUIYm^B*@@`;+HO31E+w z|BVl)0NvXx!0jIotY99f>YV^y11V#jpPp${#+nxBF&x} zQw3Iq@C3a)wbxTdvHvj9TE^uuL6fca(X#xU{DkdEu$iaBsHvZ)siptYJwnByW#%(l z9e%L_r?9<+E z{JQKuXL&SV*RqKLUmZUYh&@2zrysRRG)Lr2T8QH4ouMaPDPW>u%Ew&Rmm@+unDh*O zq8+gC8IT;?VAX2YC1-fZLmz$0y7zN9)Nr^8(g)p>EeQ8xzS{bVdAMC;U-P(;+QmzA zM7&c2C02CnD0yPVo8AWV)9ePX_t8nz-c@Ys>sZDzNgVNL#Kb-kJ)cdFLP7kmH$NBWMgb?duLix|WpzQ!TH;EyT$>6^c1U1g>T-wGD7DI9JRF=gC0HA75O{ zYe-<@@iSkEz|3>P7h4{XRAj{yTPBG7I9Il%j;+Kma&FcK15aN+A!w2=11K8t2vJ^KZTfT!yyo6l1EyB#%=0T%1GGv@!N!f+V>s1-_Tjx&`OBUe#YC|zZlS-VKZed zmAxsb5_na)&B6f)FSfI_Z{XHBqVL_#EYh}hPQH%Hu?C^q<{%R9r}qNh0Ys;A8hH1;%`m){Sh?xQ(evHv9>R&E8mbYm}0$( z#-->tLYcCSIHopg{qWN&WBWeMiL(8*^r5yBO8ZI}Q&E>})%>M^pM&QmGjZsBW`uQ) zZ`uyqccHrT=l>=g^=D~Y?*x$mAD9BEDbD}ns?jp$Kyyu3PuOzx|5?>GO~=^>UzZ?= zzCD|SPg;tPiWi@?WZDV07rx3snv~KMTLE4L9;GR5r;mcVri5Fix-es!D+7;)1&O@HZl&JUf{ifp? z!cugXj2pWX;xFD7bsbNdlUYHv1YZd{qZ;Bkqwcd`<42-u3(rds673 zkPNOgs|gDX`}X;>{B$guAHlWk1>R#L68m>s3wFc7DeFh6o>=wcZe^|@#vN;t8U?)! z2&=U68%R}-xlID*jbaj}lHRJLjeApiU7|g-gCg`nE%{w;eVqP!@;h;!stJeaH5#Z) ze$fhR!A&EdImt*J^^P3QBh-hCLnG({ZnS~d>d|sn=^G4H>h-$6=}sa^OqCn z63$rTL~$k?Qv$A=T=q=hE7lBQM*~KeeI~h|mG;ZO)2$5z!5+z9+T-HPy_Hc03=r7Z_3`EG1=Haq^^ps4qod)kN9>qSH=f_K$ZAFRjya=4L6-A-xXr z2|5lf5Sv&S9Pdb*%lxsTxNbwh?Kf*<4SnMs`>8n|7zSg!V|>?Zr#f9por1ruaejXp z=+9;@UrOPhWh~t-;4Yl}#Il29sd-L_tHr+5GIFW-?o#JI>Il~cE_o1lO46{IXBB@d zJDtc%%)f!*0`8$2H|HZgICJFGWiaYyiuPyaFcbZbHiegJGx8{@bzn!mX1}7WjqLM` zZT)O1=LYGV3C38TzYiH*cw>C0v;7gTDpGmi_aM#tZY7|saF=diJ8tfqnx$Uail7j)Z_?Q4EjTnidx%vJhuY^Sabl5@xy^S$Kz>9tj60r${) zo9b+i!L|t+|x@6LuYi#sxFZE^o(V`%2mNqK~wK zt43juYk%|Rc4|!X%VsiTTmzl1s7V#BEalbn_7_4AS_GX;H&i@7})L)P}?V-oB3BhF>+PS4q;YSMBwF{n zt6$g0OZwS3Lb-piNUo9ByiTf0WAb}Xmk0$k!oH~@(cU)J2b(!W@&^f4Wn^Z=UFemh zV~wY#lg;cCQ|Gu1UxpgUX!iZu-s3h+?~jqETXQdQxvkRMNP{Q1t-19S1!pdNjq_nw zMRGCFy(#*jPq&_zR=dBG_kJK{&FkpxU@6O0rH|ena7*=xu$`zwOD`Pb4qZ(7N$e@I zymz0$BSBE4G)nr`2UsJ2>)SX~^o?Tg3vHDxi>i4wGQ-bz?4PO~+tJEcb-sqYGqiiL zHI^_$xoGgA#YL8QAA4X&Kta(n@I8uju{pZshlM!Zd8x82@f(BUttM~m)~Etnt^BAF z-GaDxbw7~iFeP6_QJh813w)?I=r$PrDh1Zt&zu+Be5J=9fQq(vzr`G7EZ@gh7BcuL zVd)+|>%c2pS!^o_K8vVMQp&bPup?@f)~K62Y?Wb4NNkzJ-ZcTpBae2c^}_pg*L7Dg z$1#}fi*w>Sqd>vi^<%qJ+?>+oZM!BkRl5~S?-UH*H-`mI*j>7S&?`+k9EIV*mf#Sj5SeIY0G=$^$(r+nV%h6MO-%8N%Po3p- zANqC6k$guDc0)^)=zCq_G3`cCn)wUgB%%lT0^M855|tzX1uwX0Z_|7$zxINC_ri62 zTO5=k1S-dy&HOew%sxQpkaJVS(27kKB=Nrxq*OS)A1Areow?zeM4Tfylxu2)Xf$?mI$ zqwulGTLyW>-q^LbNN7!(&5)S|3*@Z2iWW^)horr3Tt-98ytV&-89$!_psT=SZe=jw z;8_1(R;ZV8xA*!-LN8a>P!~@Z{|Pf%^>yDslwPIIoIxM20sB`8bri`@67S*dWRyQz zp%nE2axzh_gSs})R^EJ9eshkfXZ`hlu6llRZhk({MvCjh7w0z$lN(njtIfB|cu$WH z8Jlpg`_!m0&5ioS059J&hKy0m6w4U(Si$MaI`#3sU`GRO4`sX@ew=9xX$*;jla*n$ zk(r|!6SqP9LVf5a8bU_RGmiKf+3eghVW^cPgt2>jhM_pVBgF81 zgOe1bBF!C*00*rY40ID4l!2PD=G`c|qh*CzK5fy}fp_G*z_D~sf2oB_w7$+T^UHvm zIdNWm`b2LuwOBCcicYYH_9&*vOx9_`w z#)C|DR|l<}@+o3;j5LVZQeKLR^2qz#0dulD{qZUf;Q34$u=)CYcaI0lb!JJ!fS|>$ zv-jQ3OQ51>i0w18eReF0RVs;K&9auHvre77wdTx8%clt@It=|K$I?&f)G}+OYfZvc z1d*jm`esYUhv=Sb%3nY{mo^3@?*yqZvIh&pR}tNCOT&oa33PT;ajYH4?89#@U~*TI z9TCll9eDliK8agzF^oTQ1IgJs!qp^(BAz-AP}QPllj1IyQMLmEBnHx>Vjb#b_ZD?6 z7^1K)aHNe=Z&HQ@=*Nv_3|(FmF;*agSNgoLs)wAhdey4{N5R!ww6kRM1OX^{btA&IwX|}O zkCuB@j*cJi$@92eU1dnaVs8A#JHGS2dN$#T7MtIsRi+>A-*=!N z?XF!O@Q8c>e24p;B=j<}6i0#vbB9FeO+mh=wjHJ5@uzG>my6-5x6Qu0Udh5D^@+Pt z@?uJtoQaPtBSWH>s7@u^C&5DE@>x4?XTZJb=>)a@n7cfIG1nN^-HF^j6aguMl)ysR zFPflJYFR?}{-N)xE4mJT5#Hyy*gG4_%_}^-S?Wz+k?u?iCNX5IvN&?i!9cA*xeFd> zN_D0GR+(P+4YGMaFUzs#s8+A7B`z_cQ5uZlSteJ%S{H`>yzvXp^LFuFzJqB`HEm2g z(YJ%5H($l*Hwj0HqogFzS2;r*&~d*Kp%Bn3$)RLQh|7KI1!<~b&Ai8_DnDh>o=r4P z;1{3jd`BZLOTK+qmj9^p=~nTQya=?9meV3OnNpIGA{le+j!Vm8Ti;ZYhC|;aeZCp7 zdF%1%ph`8wQB?zjtq~;QOck2!c%I?a^AjH$aJ{}n>Yz7xDx7nizA%kfFlc>jZ`hNf zJV42d`3@Y64vx;P#H$?PWkYgg(OHc$FEwzLrRmQnyLq|nmO3nqzoLB7YN|7iG1VWH zO-CnTEFepNdQ@J7a8qe+>VT+LW$|o0hgns?NFXGE;Cue`EiA*K9%#uU!0nXSlo|gU;lD(Q{wTiwNZ7FTf~nd(z*KGiXXO+n87XO=|AR7- zr-t$$WuiR9V)(F-IeIZ%OL!v3IR1F#3J`;XLj0|B`vPsrfV1+k>D70vb9s_d0+x58 zjlx%=KW0w%7ax#eRVd+QHm;N6^xJ73C%K5h{-~{0o5(3+d4e_DFirSnorh?Ni^B=C zzNm}0OLXrpK{emrnQzo5g{&RkK%CU(Nvf)(cqf`A`YBE zXVIMSEE{<2FJ?bUB%SNkzI%`z{n9J_>^4>qL^=JQV=BL7QCwb4-2=hA7BjK!c*Dr# z3w^H7VEelxPwhpwpr;Y@UAp(F1|_bCk(XUq&C2&;2Z1uE$Mo8`{-X>-g9;z|&j^O` zD3f~VV>8N9X_CSb$1g#9=c(BGA9`PFe88o9nXUow9oN!;?JkpI6+0>uV`fxCu!_@x z=@XI49l14LVEpeRNwn(U&4368_w?%jq)+rek0eZ_=pP}RTy19$JZ=0Smt-%h<)(s& zSwe!Bsh!vw1jQPavv4cPkr`5ZvePPlt1gOs<_)M-h1{L!LOaNwgX~Z6U59Z+nz`y? z5Bxb7@&a-9YuV2A&a*gowcfXR4>?yNw>chXPZv|{T`zoa-pI{-1mL&3nP3oEMC}xY zDkIqx*$r9qb`?en@^*a91yyhw_5CDv`F=v|vYk%4!FgT{ujepaPE{J|i@+6WtjAGn zXEqYzY^G0Xl3wk+w_j}76g!z#27$LQ_)Mb>9L?MF@zCj{US&JYZGV1$yoS0>R9We` z-*P;hBTp2H05z&hVyR3&+fDg8zq_pR*)8-YrODDC5B_&J)VjifmN_q1&E$P7E!3}x zB@t@^RYqgLmvK6+i9E9mzkc?cll4_2uryY%yzxt#$0qSb`f+{th0W96FDEv^KtC?e zMzEEQ=Z!@h)yGQain%!*YEhc&CY`s~q7BI@w0lxoJo`#xDJj1!bj*gnznf63W5S!E zYNf7iH>a~*&mSX){Y0!?)H1CxfUt>zYyLHt_A8Q#7hJqD-q@cmsBAE#>MOYIL-Q!X zHd<@e(2~n0Ud@L8R4M>|+F$W$=YjdK1)hIC!jCOc-^YhQ1H3Y~2NBvK)p0EohO8rTHfwZO_1(tx zMxv}aWXqRpN|SiR{!X)5rAkSAIQdmR$yUE(dmigQmfv&$OVMb-&LD#2RQvU;2_FK_ zCOtQg%gQR!$M4UL=Qt&!{Xwre)I%%_qmrZh6i|*GmLuR1;=dV}3*;Fm{gfp*NEnGd zpv9AS8}A+2MP2G(lzk8$id$Ta~pwUy~2CPSvGkg#Y9b3>cEMJWo5LXc)j9;}GO{v}^Fb@6J6UJ*m^RBIB z-#~SFc8hM$A_9E=S;$$`sZ*0j*ZSQ$WWu?5E94f@@cA;?u%n`yHZZ{Zy!2g~3xbJ` zx4Sg&8HZ=76UTYvB652rH5OubnT41s{rd9gq^0BH)pUE0uc$bXH@(tbuG+_MadDo! zh+cT{qUS2c_Ls-8G|F${?*bvBK4<{c=LRZ~KHE1q5~+L?6q8u)d_CS#XE$4)@~MKR zm-cy-^j!-vn$JbL{2Uox_fmfDisTqqpm|Ie zD*R3A8@CyaAT+JmRr}+}2A^__Q~pS#jq<3&cqxHK!69GFwCBqLB^Q#(=iDK0#~;p# zy#d*lc?pEA$AV91OZV+Bt%k(_4^XAJ0EV@=f%EO zd0t`!^vgYfoG+rm>+-8X#6F1h*A9gn0Mxi68x68Js%vaxB-N*hQ{%;(@&&#v$A_#_ zXQnq~U#)RFn?n2Bn(#h74Wp!aePleFnz%gmXwK&x%6Ihbvl8mAWcJ0$J@ND{^1-M% z%8B2`?~=-nI9;bq&FEwYX7R)fYssn$`Spg@Hy$OK&UqA}HK^KeH>%lhqfgG#=+Ql? z2Sh51Ne6tpjZ$v#*Dn6T6MMg}c2a`+Ij+pzFWNWpHqR z9`F8p1#E-jf4<1a*~$I=f0s1+K`<&%rnGTI_6zotN_kwABX9vC5-$A$Zgw$GI0ezGJfSa|&Ml z+NkfxR%PZ=`E?H6X~?L7?1dY~h_RF_Yyrt%K36l9 zGQ!mYmd#R$zH4Hx$H6aWi8EBs6riqUJKPl*Psnq9rWCLl^4RqWx;e~!y)KN&5lrYt z^o#D}Vj**X^KlGw7+5W&;aR2iSEbbYWmYGxt`pd6hdhFF1O-X1&gDBi8!2%QG7?*z zVqI&DBa&Fp1Op$s)3)*~SYC%`S2b-vh7`@DY5^!HM1CYB{(H{)WHvP8Mk%y*y>VVq zp{@K{Rs8A^s0%+5?;B+O9kmJFX{RjmDZo1qeN9TPulM;7-!D=1uyX6>K@97f)Vc)^ zym8u6sl*w4oUGME;H#CFyWPHAvFP{BbGiBU#%uo8r2e{GlYK5?Gii)oc>6v(+|zSp zF9ukm#`VMBQ<>AFcMG6438iJ~k-Uc#^oA#36EXhAi)c}u_bC$v&wYWksvFTgPzC;0 zIKm;7Z>affJ#>pRs(MV5GjSq41-=fH2~zKTb3tnpexXZ8&TRrp+H;5~hVHWm_$=Sx_u z5VD2P&llADz4A#IcN3jf^PZVF_y^{+ctt5tsJm;5l}Af0hb zd?wWwpgG=qc*0?^&-1d^meD-^3dQM)KMBUowLcllrrw~(m91eHNUz9_YAJuB-eZ=} zh`|{w9_=P*i;7;|?IG!qcEp)Y{|Z_0_qKO!Gv-8H)3jJG{S}uLc>ixULiu0Wh-rm) z?=>bI+!YxdoWTDzqsZ9XT6+NhTVAnub@{8LsOud-wix&>9(i3{^G*g$;sJ_|=t!EAWUp1?x zDtnK|U&y(r3A#b!ymsdA4JV0uBYz=2|FP}X|LpgMD|^TFH!M-C&&sb~nbEU7Tm-;r zw@{0--(7ry>$v;!_$UeYrf-P$+5#>(D)He$-u-Hb)Fk;R-|kKZ&iJl4QVkKipFmuU zyxY$xJ%7s1N549M{=D=BV8`R~$``{F<$LU1@*C5e9cI!_(r%Tzthbk*zE2p@*D4q_ zcNbM~Pw2sHu1`{Z&9o)Vl12ljNEfkJ+{Aj#_1L_S~$;le>Nq3GVJrFy%SHqd|pVpy@eNu(B*y6h5Z6u zK^sYiz)j{Wok-TXLodB|kcwT_mzi^c{Fo5BuvDXiEWM&=0}R)NT1u=1heFl9oR^FC z0u@`Vq?7hOQg~FpO&jcd3XvJVEs8>>xVWO73@CXXlP;oW^lMYfCfz)n@|(Yn0A|G) z-mR~>8+AkSRY35LA5%y?8k6$)suV4StVf5ITRsW7=qa{(V~O54ak1Ch3goGHgZD3O zHF8Vi?U_l=#`X1uSAF?%>)kIVLwDmcn;+0_Dl_X+-1<~)xUI;uI8UDRY0|j3xqsk5 z6hP_S)i&~@sh={TIki<*Ha5XyKjl-s`OMRR27%hvc?3%bYi}EJr7b^B4Nl~YeQh%< zVel2n9zo#|P#}Svidd|+TJH4y7UADvbNPIoWDr>v+>ylPuiF`;t-wTY@I;`NT|W&@cx?#1JoBa)})Mb(flbB{l401(cD7Yr`7iWzS8%T z*PgA8{57`mkCh_t;qof$bjaw4^Lcl$_Fvhr0J^_wY{Y3|`&WDL2&+d;-IUnWuT6r- z)^`<&nDkPLXkg`#ucwq9QUMPdF9yAdKVxq%>Qe&F6L_iU>1Ved=(L|FPPJS}=w4I7}8bGHVn2 zQ%vNBM8&Q#eOfsrCWGmvdggpUYcWa2lU{IrAzs=5$y%iK3_Hc_58NE>uV*cvm_W%N z`bTOQehR&IUDEr?Z6kNTe$4*k3b@6yXTF{{sgd+p*~5aF!)WDv^@YYV@FKc$b$n__ zYnd$_DqMrH!k+_l#9Pc-$(SIqEoNMx)hUUInY$+Q_(?{nb`)Q_hDib%Cai1`1f@#8 zsh*n?di#Q$&d%`Loc@xw4;>%WqG5@;_UBi_1h!s_3bsSpa8oD9fQmp>Y_@DayNkJu zww-O89sVlfp=yr6j0s(ISuFYIR|T=T78%{`$l96-wM_(-0I}reO#WZPdF$=M)Y7Fi zgG}VqBLQzejgQT#%Czhm_Xp;iOFG3`K@<&h^W6P@b2ex5$O>rUVP{Om)=F>7`- zHip(vQvSnj3QpC}ir>Kn<21)rsEi%f{mx}NbcJYT_G1!R*eR*N=BpazA!Ms-AFJ;v zw)=N8L4KDwBBRw7_&c&g9$X*)Kf=B#u(B{)GgU#wwr!o*so1t{+eyW?ZQD*NuGqGX zlcZuydiwU1N*F<$A4Gk}J4>+-RCg znHCc>s%L72j7yDHd}B>xzx2OQ@0&v7XmQWDP9|M)tZ|JIUruWFmWqcM7kiGjc1xZz zF%vgAwC^7_Krk7jXG@Kz?p)E+%^L$2GY);fdTZH1h$afHL-7xkU>1KOe&XOyv8gaB`ExasMOO+b=M;%c?*pZVoSP+bC~-Mv6h1b08N0V+bSnu_(<&L~-OYc~}S)t6E5dOLsbz<5)&7#*ir?w4AHR z`O$&NI=x2iiV2kywN~X?Lc^g_{C>rDj4RY3r1ER4@!~DKNct(FT&#ihx!-vUE-89a zD0$?@n?9NJxxew0GhLUm5O?5YaYdJTU+UD~iLh_X1kt00$wEZ5tV z{qkrs%8#yD@Gvt-WrGyGTrO+DIiH_kJVBxDON7BJ^#}WQh1mEt!%P(=;(4CiC3zW{qwrsfd~}Rg?x1QxmCq?C zC=iQOp*WM7tV4RwK@=M>g>*}O0wu@?-W?p5+lA~-LlliWauXP2`R5VRH%$K5#_Jzm zsn_mkmT8nZk1>at=su?+1`ivIf&3Q{7FfOhwRn>a7PO9bn{V+n)lI8(cjnrIu2_&N z#wdd=DrZ~Mn}IyJN0U?u>~-nH5-ud9)psmn2E~@^z(PqNb;P~NTtnAXXyCiavp)QQFn$4j{M&JDc&1t8*+b-epyP(2j0l<~n*1}93SpiYDBeyR> zCc|#x9#J`L{)zQQTU-`D5SQ7tP1aJBoHQ4dfiWZKQ6RN5*b}7cKl?z|1l0u-2*y#; z`zt1`boV>Uw7(Q&QwUdaShc}4vg`ObeKVX(s;nJdwyvj3ewlEyBC#Z(Zw87{`D>Fe z4yX}3XkjSdS+UwxiQe#OGFUVP+PaXyy8A0k(r_Rh<}mnM0+R{y^{`hP#EFlXNOt|r z_!AoSv+gq8)VQ9C04sIJicudT-#_ri^)Ke$7mdAc%2lHClIp8bj zcJlLNhi9uPh`YjJuPc?$r`=`X7kGI2|t_dDBk1r{{#6JE!*ke6%XTH@FcRF_`xq3TBPwu-@On9!JG zO!EEQs7MY+%QLU!y}zMu*xv(+JL?+R*E+Ua+86b8col*T)l!|ok`^16_!gViCEhgd zzY7P?mefz#^1a(oC*f3b=YvUZSfDH$yB@Hz($6WgtV4r6O2f}(VIG2FY4?C>vZ_cA zl{JLmZl>#joClR~{_sTiyrid1R2=0csV{wGvp?~6e>2qd4nB|61p>04KZ9>BnL&`(3 zsXIxffEJ~~U z53Mc1tb3u|2HV6jBj0VK8p*(gCFR8QA|^i04$(Q17j ztCR4>8a;jI?!&NXWvDmtNgsNqnW(8{^6L>@_Q_`ZfY9?ssol{Un~UXKGOp_q3+`J~ zwCXx*5zR)$S2K_oTRT>^+7N`wk*}`*#!wz|Qb@{B0dZc+BUO=ZnRNCJE4GSl^3GMO zxetI?CT<6pS{&PDuu5`ri+7V1rH>yDl?+^W4Tb?rb%^+2$`RUTww%&Bm8KKcP?h74 z(o+^u%nLl&KCOJ_|4-E7A9q;Vw3YF&P#_@ls30JG|90Y(uyri z7<%}r4~cz^vLVGB6??h@F90}#5ej8*#h-YK@}Wxo-kL+DEMPYlMBAl%zHl`02?Q2s z2xT0F`AA}2?($oKw@*<#_;YoVO;7f!_{U%)9&ous0|oa^-*4^=_wmv6ZuTN|wP$W1 zdk%&Qk+T^p-KB@rP*1-0Gsmdcu^Okx2YuJ`V#J0ILKwP+27kcfZ9#*L>x%&g#fmWn zA3CoJOIEMVo7?W$=FkTd6fI(?V>Zx=?>WlYgx;v0)m7@dccn3OB_H4|*)+Ki5~s3? zg@~T99cVdtM4UB&57Q7+8k7d(ikj&u!(;PuyENZsL1Zz4qQTDBa4Xo3pfSgWVKfy( znWdd*5$|sz5jBt9R}D=+iG66n&X2QD5>uFihl&E!p_vb~m>02Nahl`QZ;Db%1X;bI zKopOJWqu2-ZYLKzZ^?N#l{YL7LZi*r?ifgdj9)fUp(*=gE1U%n z*fxa9f=WHH0jAW&G$L+mW|^*d;+)qB*BLvc$p>FxFr_*Yn^B&Ip(=n+vm&+*w+=Zn z`Wj^wISuBq;3}HvITp$=}a>N(mSWrqLYXyQfOyM2?{o?aFQZ*_R+ujJ0kYx8;q4 zq2etzvj0>Qaeey4=bN`5YUtzmJaI4&BzaSx;mbE-uvG)1;PDSls|%9+!p%w`#gp4R zruHRz!+`NPp5Vjl9jtX0Mw&+&VPo4zt*k+Ok?wYQh@#K5R>V^@V?tfSZ!WTSOwdHC z7v!@*)nh`I8#YwnHh4HHA6ux7(c4dm*gkop^Huw!^CJ%R_q7X8F#kdMI;M={+W8a7 z2Pv-KRLOdKQo&WC@EdsQ;X`dxlGFIv6|*3ns~*$D-XzfQ!MqJ8LG@3%a-*BbRg^G- z=%AR`Sn3W&>1gS`-BTyeNB(|p!e2iLk~f^sS)iV_f`f`#B~8a(zlaW%;>IfR9|F#| z44a0_vdeRs2$kF@5k2CwP9cA{_Gt!(ZVeS4mV8ttJvbjlW#8di7YBL!_k)7{aMWj$ zoaxbQ5uJC}`#f)#Y=zo~bf{-|?kXI}?A}oH80gQoabYMf&fnDqdOvaJB9H#@Dfi~g7lPDml!97;C8qmW>7S8Bs3FJ%IrF~s%TVx&h7^y>)Q|N07-6TqFi%dufN!6AgZag|YjV zLG-Tyy)q|5qO_)>n6V*1^iM!hzQqhrgkKhE%+Vux0T%K(DLpHHgYF;A9$jz4PEl1@C@u*Rj5t_g$t(ZZSRam3(NEM zOhD|U?cwG`hN|{J*vO|?N7go1;53;O+$Sr;Q93ugpWSiow>E{r$AC4Kq&0!Ij`KOn z4uY%1v?V~;-qj1sf>SBg{xIyv^=1AB^C*9+=Pw)y9g!F8EtZ1sl>h>(`apI*%j%y{ zt_6|E3$Z#Ya2%!Ub)hdE9nmLkFLQ;kINkYo8 zg*J$uZW)lwZp+1t@35vbwIR%D3m#p0Ui0zbaR#)Ru=D>BCjbX*xmcvbsK9 zx(mr!1@*)u#X~o@9xwvi5t2=aClItkG(v4iyem<<)(+a8;UKLE`x@?SeQX8z(|u0m zMp#Sx@R%{3OLd*-CV|d1sb<;Nu&EOCsTZz77Hz4wd#-ncM>F-*4%W8Na^sJd0!x)1 z_Yv@%TN7^K>~agS9Ezgq`YqiPZg5WBDdY{mt-g#Z4oW~5g??MOV%jplK&3ZNY+Q|G z2c?4Niy{^DRGr&>RW-MMG0G7Za=~5$Erq}@;xjrJ! zaE3c**ptdwfU!g83AuBEs&d|bbwSgrimnKxtoNA#+-V3&e z`jPOg;|HKt>(BA7Tp-+hTz^C&hjz?Q`n!bL34hcYx&07YKQ&HO*|F(NocT7YaXsEJ zl`b37mqimRMRji4jU+)Q?DHwS2TF?C8e9DtTidu>JqDtp8#L9ISf=?am%dvCzqk;k04q*x22yQgnShr8!DU2$(+6BOMb zj7CCJ>hl}quB1&yrf8hV(qMC z;w*3A==3jaFk4m2Xm40glu9@-_4j*?idY&PcTNnsdVTrIE3lbk2i4N?}t_1<(FxsJ6P8_ysz2U++Izc zb9R28PmsSgl#S#87=7Fh6Z<+?7$({g0{z;!L|qga;{eilwE64tHe?}O&RyLwBP6MU zcIqR(Fe5A&rdtQnI^ql~CRLFW7yl3W;fyF8*j=mvrY?;TeM{$LA{ILg&H-SS0dUCD zBb%G%r9&b|c#8hysNxFKaKk>NOJ=}i#u2=;D%ovwy`&|-mRnSylB31UirZwq9JR^h zN>zqoy1TMt-;rW~P$g){o-KKOuGOXb46CFiPmRfDAZyn%eb)8|DDz2f@h1dOyNSmv zRbW&T-R($b(}j~P>B1QAK>-z;F$4=@oxBm>&3PJ~N(7I8+~hSz-PcT&^oa5PdYa5w z9f!>&#wXO+2nT{aGSXAyU}hWJxSDtysm5L>z@V%#tuxtFz|50u%RZw+W$re|NWEA( zlfufQOIRek*qNMr00CZGb9)bbIu_?jb9G|3ZtLFYJKJLBrT)XfoH?ZP9YM#~!!2&o zN^gxAnCPA8=v;S&Q0$5B8KuH!E!bw~`yZ&`Th~RZ8>x^L;Xs{Z8$n?zckJmI|N6nJ zBw&0%tV80idMV++Z+F&GY-uO3}oWFNkP0TFEgXnmY$!^6j ze2f4(wndINSg#yED~etz(#IaaM%Ozu4yByA;arF_wBjMDRT8qVh`bhr!_sZf!)Duh zgH&ISEIOBwU%Qj`ORnf|@uu})y1@lg_%WsbDo5G_^KJ{2LGhRl#+*?XM}o@B)HpWB zkiLQiAY7t44|_ILP^KGOy!AVhL*kkr2=gnPPU^Ce#WUMew40^n$3r&%J8m=J%s=%s zm@P`ln92n)X9Q+}xxgzNQTX=9**e@VhU{}^RmWV&r6B+^kvp~|aD5Uhe z;Y~8Nj}#5`OLCeZL91W)L>t1!&|mc*;jPMG87U*pbbSZMG|YU##GD_>q&xK z5+$R*jmamZJMu2%6=tdFA&ChK(AdWe=dd+U!9>n`0%0hr3kuo_1Gd|*Co|a-B{B*= zX4$Vd+^*Wqo~PQ6x87bBDsz3(!j?EvI?H1~>ESy@`|yUGLES977G?0aj`l8X9UW35 z-OTUhp;T_c`@59z*EhV0^okq`Gdn#}MRVO8#0weP%G10Klxm|MEpV6ITOrR=89?b{ z%)RS}Q_XQ*fO(ndP7^YBoL7597bHkd+w-?^ zq{?!(mHSig(CB;SWLUkEd1_pNthN=0zrGZr*Dlz4481>ujYEg+T!C;*?{xids?WD< z(RNAkt({bVuI+&WNN=(p7Y@KqmL3Ub-&XrBvHi!6Cm-8er=R!T8d*SJj}60yZB4<; zw{IRBMkd69OhE?0=NZV{k-ML->FKlS}i){n4A{<9L8r?_E)`6v8n{;NH?HVX_t z#eKQ<=Xq~C0Kw7ghWkb>5EPsLOZd+N|Y|JuvKcuYQzwC&NedUclS|&H?E-#N=)>5=G#%Bmi*j(7z zY;Iehx!*2rq_?zlUPP73p?atSEOMT0obvFbGH7V}O}l}!>dECSR;Ue*SfDc1ms))s zG*-@1dEL$3MjMP98%XBYW9A8Hf38Y?=JEb+BD@}v`TLPF1tQ$R{+y|~BL@~O!5*eB z<|Ae{^Rl#oe^CdS4u^{gMhnRT-p9F_2iN_^XjMWb0bbDAs5C5nx}NctnaRyW3pXiK z{g?biG8%B`R07iXP&9h(kKdWS``;a3tJGA9-_`=YhQw)(c= zylY6i^>WI6MM+IvO(S^6S>W!%&#qb`)aVct>1MiaU|&Yx`>0eQYo`!zxVYV7i-%uZt+++ZTr8|)CulL3DhDT$$=PnBIHHeDy7o{G`RUbe8Dm^(q8 zQKkjwH-b%xp(RYoU{dXfWmzmpniN|?-; zVpEIuhP@bJ?P#0Ft-?u_(lW6?B3JM=Vmgd)9!mSe<*DiCFd3;P(fSUUcoHUDLy4~L zaUWci>c!u7#?hN?1xbS2DVFP~=o`<3(Wzi4kb%OCP299pwxrzi!#txlKXkmNhjzD= zdkDe%M~RA(f3DgjWwIsvOvxAUr-SM!K|?F`XPNBCNhM0(QRw8;E(<_g&%X|o%S5Q9 z3>Prd43qR@DQTQ16{kTPK^#l8*Wet3YwR3od!XFN1QKVW0C$O$VgrP|88+tZaFBJP z%_&7u4|#HO88H@cB^abgp_@EIPco?beYVAegO6eq=OX=aC9RQO#P32n{-C*EQ#0>z@(|HnS5RR zXwhX^gzKZlPsSP>9oqMh87o1op^D`V4a-ROWKlJ&ZB0d1+x(o!wLO`}yY%_;J$6`K zC?asQVzoGArMJjxxgpPG5tAA;MTU|nL|U`DYM)QM{pNrhu>D@PG@m?Z{JSDUgi2{> zaio>G@ejn|Z>lvGaD+87tx?**4|TmFwFR1saDYY(F&(zEs+W=hFr51_2$K2|AE9{RHWDUG+i2m!xz4-xu!!Hi zBxEwrd56EMKN;%Y<-peq-NzP6in=M43O=VD)4S7XTlf9cz(!ygPGy3K1};>`?leL` zbG9&KOOS!@ZiVSPXJatSWoyWrc_^4vBX1Pp} zhS53oTkWU2RcdKoAgD5*M?d$7<)-GI*Fbo*B4TlJvMG2Ub_%FvS?#pFju_A7qp&+; z&xrF$iLmz!Zf-CNP~SVNR4U;C-N}@gwp1#xRASAKCGr{9-1>R{?^b@4@{iDA`v!I- zg;H_aM(&&wI6G)KF{Qb0SMu3iv}AOtFt_8F**Kd`ubGOkRBvwKIj%{2Mj>t1#jKvH7wi7kDe$v!|TOmT@SANN5& zv zkWqxcUn%RK#@uTVUE<@TSD4#z%<;#KX*L7+U@6bvaC{YDpXlZor&n{!Jp(jnf4Rer z3{vPf0vRr&Bw}bKhEidJkw0f6Mrjw#v@K(X^&sq%{>bN?VF8rkb5o zV&?pV6Z1PRyt^v6sS68!FBlLYtIzcws5^@X&WYX+*D)~4Z>GtpF%OkJ|Nc|6%EKE( z5;vI3C$NXgMYXBfmfDere##jY*y|iRo_`u+=*buDe{mOlWq+sVECz+|ypq4az@B_5 z%o-GWc$5MWK)&=?yc?`i9cxY{tbt@{IryU=eVVjkv<|RcTu`_+sv?)QU=( z8yf6K4V3+gqbpv{FTCAF+$l469Y*E)*6I3d%JUl`&La}krJ9dFrtLK55J#RhqN)Yh z)l;w$S=DfGgxywFLdF`!$P5;<^X<;mdjA|jujWSdr^1I8jAr4J`8YHS;Tg(3eZ2mC z1OtC}RBI>BrGK^^WT~sngmACupUQ_=J_2uZS+~Y*E}|3v%%?fl9o^_5?@?#EuAb;trn@`?^pg?$>>Ae}_FYH~*1%SG{zsOXEO7ak)pR9bJn{suz z!s3tk1s{}Pv+E;Dd=;0eDl$>=2j>3!0tRk{EDH)z3kHLuO(c+nD_@PujZB#iIwhyt#Z_H! zm>1~!E_gD^2J}5z1XP7@b>NNx-T};+HqL%bX!wIIi`-e_zsX-kAPA!;tqepjx7;U; zE0KDp(v;EF>dN!Gs{xd$w22Ma_Tn&Zs#%pqa-K;hTrLr;46iL^(!Y4G43Fj_yj4tZ z6P;vd9F5#Jtcp3GzkAhy83^?JG0n?Hafflgn%Jh3_ZMK%Y6VY#8zzuBtVRhX)0AYF z$3vnk^|(j(qycopB?Z>}@F|SugZWxw=gfTKwsK;Vhp=`6BhWi9`uNNDOTqlzCoy^p z^ktLng=yxxel|7Gw>EkU)VSdPWJbAUmPFs6D{le<~+ORS&12fy4fE;w@nMT zVP68-*5F=Tad<)R@z^}cPq=NIu}%w>+Iuz7Ny#IBvt z&xBgv!_N>j&SLoYjEK4gezZkz!M&icaeaSDWa}WfFSWk+eS2lujC^dz90&)yf6uce z#oz>bW!NRHu#3jjj44n*!E#pS6ypm zRE~t@-1(Tuazgq6H{bCK$7lq2$Y$J6;1SvB~` z_9H=6fUmF<3QU!D+n@7Akff=R?849B#3!WA?>m#3>WSzLmvOu?%>nFKd4&;#T>0|lmwztE5_WX?PTT}ymik-(m>KOr$YoZFq$m;bg3BKrfM)U-1>#$glMS^;U zbb&6|j&+7(OMB>n*VfP`q>tQWLY*$7YWKwG@7>!4p~tyUx-Z1cM${;1uI_P5qDfb) zh*_W&f=rA=#@1__Xqo&)`mPea=5o?}OpRcavda*gaDzUVH_r6?9Tl~QyP59|X^^P=XJnqK{G z;{EEOdIfk7$YBS)&$3X?opw^~6H;cEw9=YTZx+0Bq1LupG;N!zkqxb!(lEh3b;;o5 z5IiS~)-O#D!~9i!8po%dY;_%q6xI1{Ep`TbVG4g?q^a8qPhR0z}Y{V25fqq=u)hh}`N7!1A|U1EbhHgHY*Cqe|G_vg~n zgCKrhgh+2`s&t-iq#kftl7QI#0W$lJaxoGOXLfK?0>6uuF};Na|46%8>>GBHn0;0h z@q1o6C!(2vJ=wc}fPCrmz1aAB2kWh4%6$5V@D~x(2LRn&RsZMMf*Ne21DZNeX9`@* zTnUlht}CL;zu`Wm?m|w>~bbZP@NL4+e_3mN9ajfYZwxWWnT^sbHqgDP1Tx?+{)d z2%5{6?R>2rSLKDU7={*67XUVn@A+Z9amwq<40b$yGSQ z?#vli=2Xjj!}x`~Bx9}PPv#P}ty{+jqkb1VvqbokWU~TTTH>?;v=XL-yO*K?CH2P- zS99n&AnV8HO%#UmT-B4jqUcXD7y^>s)l0o3eELd=vW(X@y2J%%cUYXV3X_E&| zBkK&Rg#GUelWc{`;R@r(72InC^4pONxWfXHLVmM(g31Zqu-I20oVwFM)TWy4Oh#kb z(jTT%uKJ?lA@ra0qc_h7{Jum7vpr@4(#aM zW^jYieg3G?{SWmwG4~^rrvtgVr`oztyRg1(3y@|Tgo<@I@vzJ|*K3hI6T_yIZfa4` z84vs}E!Zvaiil3Yz~r5We?)vPMh4)l-q5)ft+2BibJJw#BoD0+wChjQ>|qxNg(&fI z7*Y=~fd`-|N$aP{Xn3F=nrud_nuJm)2_+wklt;4Q#s8N|PKRG`cLpnDS=OzXq;!>7 z?ShVt#4WWeJ>JP{GiUQbJy}1G-$@j+Y#xAEAHY7TrpqLWu`Hw3o4PQ0BTJBfa?$^| zA!_><8qd^N)U+%ffE~nDe~Vmul})bQKrqh!jF<1OLv`EC0{06K8bq_*icJ4aT4+?PzJvFxob(vR+VyPmVnwf`V60;T?ec zhll$Mnfr^0Zq1DY2E4P7Gg)qsd&*81;{KsG6Qfg{D-e3e2zzbr@=s+lNAre1o*7`v zG>@&VJwUB|V26A4$3z>_p%B|_fyu{9lwHAV2 zwy@R_?n&ERn_yq*7s({`V+gqwt&C-Uc>M>Us`lww`R3U0oTYCG?C@hQ%W)b_iSp6z z*YEjf*v4(kVQC8`NuQjcd27pGGdAgWjh06GOR$*tdFiM-t;m%N)@9Z*D7oo!zK%@K zr9vNAN-2Km%jvg|X>MSAxfID3V-pWOk}(W(OANUA22FP!YPzutYx-6*-b-VAP9|MI z%{#W=rSORw6v(1e%9hTbn$|6S=lD?p>K%B^KiSV-R#Lel8+rEv!;VH%BJfW0pNQh?-->EJp~W+AEu4nV=S?Y^ z+HZR2OdE?QAH_423bGw3JLlTy+s00AnMWc#&(#5Xp3z7hn)D~O`DnMkll|Nl`O{7| z!{}JuvKGE!5%Aq?DYJe#7aLuX+PDD+_-ntr7e;-Yzdh1;W#o@jS13$+A;pYMnvTQ2 z)8e>kvRySjCW3Ia2lN`fZ*##<};#Kf0FLUz#ID^L65~QEbJcst#>Mw9s z)T1Eh@Sm!{y~bJ7la}oXVu?wZ3RE6*s5l@heuofhDYiiK%%MmwQTgL8G*4~2tLoBJ zyTg{uiA^W=(9K%;XitbyoR`axh~!e@irc0~L;dkzK*@jH_RDyuTp@j#5A1(E|E>AJ zKNXYzA%6USlD^_5B|!nG!P7P)F?gR9gnR+2GbfVvgEIAPWsvY;JJd4!X$k33=}`-6 zPP?E_@`fb^Ve`qWq>r7PpR&ivWnawhesid-0Jg~Pv z1()~BQR%Pz^2ewqMJt>EL>*~R8XP9KOoQb4nPn`;H4O>&FZ|1m?@o3bbj6)X-o$hU zZvG01_jXV;f>O45F$@;;pQ*|08Hbm-5VkhsLG4?a|SW~tBqYcz*0n5AZMJq&znq_j_giT0KmZNI^ z$9O>>i~SAP&PX07?86miLCqd!?!!4>V~t3_8Cp;buhakaX>08LHJFPcEnYg5;abc&|zvANe(u)f)@} z=1Ppkdaw|iFCsSl5KzxU4=HE<#KA|DB3JR06vB4E;*Bk5`4pvZK48Y`4WFy#peTgV zLnz!+wkJj1Q$?tKYYk5KE*8BnItF-O=!yS``tCBvGAvVDrZ4i7`Z*;Vn-RK*HCmH% z|w_oN0y%T%qt~ve8I?7UToiWy#5UjdWrNLYweLH%(-*Fq|TP}NS}(| z)YB^(keTM*o5_0d9%2@Lhs(4lr+M$<Qbwzv3jU4`tEUuzN1ePWC}H(L~FGhnAP z){Jf9wNYU-v{0*Rh##Iy%${n*G*{@J5A3OW*mmkR7UV}6lDu^{S#A}51vtxnWLXum z85@*E>{`TQs2qZo`)(p=YZp$Y0tb*UpxT5jz*xXj8HVJB#b?u~DNi)H#P4=B5bwe~ zlc#TB!+Tb-oR@so+@K{cdwysyOPiw=kgVq6nPUgPqm22K4*Y( z@q;uewgIdd1lZhT3-ToiP2UD`?7O=-rzTVurbiUIuJWlbT3#@)H{!xG>m12kk#1F> zs+_vBjE~pRV%sB7Wh2Pfv=bQ&VG2GslsAJwbD969J$Rz7hnpR3?pNhlq0iQr2}f!% zW}g-4&Kc~lvrzwfL%4b$d@@KWD-&qjtD_qpM$O3X%*j1KH|VApr* ztOA}14~fics$5qm#AE_0kMQCgh^UoNC`VD6k22Ug#o@eEm}8fXhRWC@0=?ClKtqQx z6GInAhX&G_-?^o?C?xg$7*E$yR$+%=Tmws8>p#XQbp@Ii_k+opr`7r0gAh7P-U)Lq z#atE64YP2=D0rkMwn7f#b%-zEP+ZG7MtQ9|MfSAH$}Fv^+N#FPFL^r8CPOiqPtzz~ zvI^`tG&DRe$8mhPhN#WKGgDFue}|C$>B=6YTFKGAr+;6xbC_#_5%g~5G)S`UUA7;# z$w2J0)Dcc&9gSOrmjEw6(0Vu2=&;hQ(mUuBYr`0Hme3eYjo-E#-$}G{*r1-8wA3EG zezAH666_HiX9aOU=I>-9_aGtl;|2!J4{i)Og}n|}Gt0N+h@8y8_M0IRt=N|tK}4J7 z@llX5YwsUGG>epZfV0}>^;`~C!8z}sUx1K0IQGgC+RP<$4Dp zT&ogynWp0}=O*-4@D`zPzUrDC`6ZmmFRn$VCYUfd=i$Fh8QlAHKs1x8i>TU&ks*Bg z!e(a0Vaxg|B)$p5>HrPx68$CIU+cXsnTL7mIXvebcMXL z^24g%T#7Q0zuXLZqLR&KUBvsDS6umKla^%j$?|zKW3mN}h+X-r6D5jo7c6u_Zoj-h z$9rS^MtNxmP8jd>MTKBf#RX|l>img1GX$gxV)>VB&A?&x2_O`HXHyz5Tu+KVG0=>ZcOwvG93yC^INjA9W1X9#Yw`u5uGWbSSsn<1Uk zq6%O?S=^-cNBjtMn{PziqLC6xZ?v1~w`oWtZb~ce)j0r|#LMi!OYGhp${noZWd3Jc z^?z4)=dVTe?^a<`FVYag#z)`0QE=gB=L+voLt|J@Um29?bEc51QB;q5ZD?CHCS z^>K{=BHZAQjY}m930sY5!U@@3$u!c&z6I0ojHj>JLfcMjG9e;oM`;LcSGTT82n|7D z_pl+0;hCvEBhA*aAZG@p*Xa-bB%P7{9*?3V=m6ksCY0Ni|u10~uG37i_KP68MPta|-Tw zqVS^P(%~fBduW>;;Dn2F-Xu@;sv}AI| zd3}pJS6Oaw8K`KJ2>D&3Lg~~uP!#VKySvCHrb zOCUoUMZ#;0TEjM@4YL6xJbbEAvKu&^F}DCWUIS z!Q1C(OWQbAq9Ws_ba$FO>6+%0q0~*k2qjOhoxGd~y`y;27(5m^{daQT)~<6d)$-pn zuTsU6QsCYAWMGXa>jrVu8X+m z8ez_324aP2SYY=vqR`+hs+fX4<9|*t%Vk->S*b7A`OCm*wGA-3`sQPkJ7f#Up5lWK zoU|Jid#x%v@^{)DX@~4=D-~6W>>Hd!Vw%;Do{%U`Aiz%`e?yL6nrdO|T$S`2^0f8D zNX5P`Tqkq95Y}qcPr}y^)1}BpqAO{R<$-!XV4n482t=K=FllNTis{?(j2kyz@7__- zCaPTghDof4IHwLt27f)HgyFTj!Y!_c7?s`sc!T-z7$i?C)N z*ivH~WLOwfX|-MuMjBU-y|zbTo?5q@ROacW;7oV~{JUHa#|LDOfvV-oa0mpVogzv` zDg7Z;1_Vt^iw_I=V=wS-kHtY|wyLCJ^?F%71UQDhZ#+A!({{;$dH zpEFnwiK+C-*J!-{a_V3g{Lfg#t zkXzLB_hMr3P{^!t%*Wi92k9SRFUAe!M*QJ3^O;ZtjsO?%8|M8K*9q+3_>p8UI^Qly z!%FGhg!h2?S)LQ}m(TgR4_K0}R)6Guv7;fiah~!YX)`%=-vl|nxts<5LF`3Dwc@E~RWB49V9>u~XYs8PsTs2#u1VG_I+)X>y zDOf}fHE=o|O`Jdw)s+T4a!4AgaXXO8EODGko=30AGwtg)35oXmjdi~jE__edG_y2Y zUl$H>dIs#8p5gf%##H_KKe$VCq^c{@WV`JL?YDIwnyp<7PCj84Hw}K=YJr{%NromR zQ&9{!*C-BAF-0UlV6FU+WYI2etjK^{IBmN9rah2B+!6Da>_*J|`V)lx6ME}+^!JTY z3mMr~?%X^&)y#@@VreZv)v*$I;6xEZdz$XgK31Bx4n28Kmyp|^&@Um?vfW?!r-@jK z(+PDg4)sKRgZu`es^9>j6e~|&c4*NjQMvnlW{7RRzpvcJAYHM6l*7gc)c-!QzhuUd zM1Q5uy06qp_3u)rjERlmzj)ozN>)nq@`${xGMOyGW%a-E3_ViO!{oh{xxzRUU8sG3 zmk*3I4Puk~to$hK?e8sM)--hp^X1b{blp%p>~gQrFwGg7E=InTtzjYSyr#e(xo5>KR zY0)5`B`)Ja#BOaDSFO|{WcQnO?n%|EjlIA-cW+ny%9^&?W&EGV%XPV;gtXHKJ^BL6 zj14STEiOl^jlzq4y(%Yr;R=1sF$GD&1edeG`!WCESFdJjNW)gBSS@xmefKw2(BI3- z$!os(-xA}fBVj1IHgM3pW+XT ze|veGD%e_SN~eL9Hj)HQ9Aiw^tETVz>lGy|XRe1DpR*W!cl~dN5-+Oy>G3m})%4r8 zr1ZQVQgJRhNN{SYwEaPMG8vSWH`ZcSP-m*@CK7EIVrt1SSKEuYJ_gHxPzoQqo1r4gd{4Yzj ze`Y|<;(NoWubB4yis}E>HTysAuKs5y`=4%R|4M^8|BP!omgw@KKcQuisQyi8f@o+( zsA!=WFs=}TKp5cCeSVq%Jek2&F@VHCRTR1-h;w(mAC+t)_2wt;u?f#$SCE(mkF1fufa`?)vX!m< zh_Sqtmv`EHd)9P`eQo^qx2H&^lWx)pO=>32u_d52?6f99hPU{j}qNj z{Q&uTZJH`3(&m0PAdD$XRT|DobwhPa&$<=P6xyxU~r|vJ( zhz-n_iX?N&&|Sn(u;F=q^xmQy_su43GP#)rwxi@OOf9pr7wGoO_-cUF7;Smq>GC8VAwTDw~Wy*TmsXrZVZwF zK)yNaZ>J8Vr**T)f0B^BNOoYzT%}yYh_bnfca*q6-;t4Qo%wrZU=vkhexPm<&Di4* zn~mzlzj#M*&n0_96yiB1&qDbFQo0F|T2czFcd?JdYCxa9ZqQT38T*si*$1mR~FW%wi^V}*45Dh9_R zbUFydeuw-QOk2VY#Hc9hqvata(u^~NMg2rkjU+~g-~tb6^vn%#rMm>Hs^&FCa$N|e zw3uX5ne5)bR9T(gj3Tk$VZHSo)(rpeqxv61`o0x8_I9>T|LN(Xw4t~lkE&C;!mJ87 zBGV<@lq3ed0XC!MjE_jkU>Bsld()-e8c++n>J7Xx4OpR)p@(%D$*- z`Zm!$`S^Hzi#XAE<*)!C0E$3^#vWJ&d{keKl6m9;BCd3R=-na zJ;&cytN7$oi$KpU12$78Cv)k?$h1ub>0RRYa_kAusZ4JE zhLJ>|q&sW3It#q|m}L3HpXw_#TfDQHI@mb3RImqT-PSD9mE$_Vqg=8BEbe2dgb3Nw zb_%oenEm$HpP1rCh*%+YP9bxq_nC)I`)M6He^znE@AeZI`)mfvku8NhnzS_4l~`d6 z_o)W>yIm!t->lT-_7$*|(qscB;f|Z&VFTX?Abtt2o9ZdYvOGZW@@jVoUp zgGCn#WL(SXv(~o0_=XrWMa4=8^KIFy3g5+qF7}pT{h2UH6m}FQk6$ltEb+{#}`S;Zg8; ziM@8~l(xlZ{B$dS;1fTV+hIB}`7jVeZ|w{&)}6oFb@E&snJURY^MMg(!}P#YG^w>r zAz{w|*<hJb*leb7@lj+V^tvP` z&EPUS3LnbTBIdPL`PoZBd2$SrPhzr$hd9fp8OV5OLPf$LU7nNrv0waHdMcWUl2O zv&lCiJG6*--=(}~)npn$C8FdqUNAoB&ay5olZRJBvm2OBxOTjm%%)ea33!3iMq;8M z6?IyFX&_ZZ{ZM4&a3WmSLUhmx2}=qR>E7P$Bek`SP*0hQMuV#KHWLxn6b{KRtl01j z&sXD`&por8Vxd)G!eg77ZL&k3XxD0h3n_Nmz@pWoEH5@X2`}cIcWO>o%T1=~$WU`? zH!AbWV$LQ_n2yq5-J%itiO#1FX{!P)yi%BMa$sAX#B}lQIb9$wTzTkn&fg+)_1>5F zzUquwvLSvf4=6Wp^@?^Rs&lszn4s-zo``!8>?_R)Z*mI5n5ckNy8IQsQ+?6VtN~zr z_^W8~=cr&k3^^eE;gS(jHpZY8tWJZeI=}!$e*5?0MQ5GS9efD(RQi!Um;x;2sSux# zUIPM7b2Y)eDFx;b8j=-sed`e7rx-MH=55IE7?t`+NPvtrk?!jEU0`M5b22H3&I`&H);!l?q?YHSnWBExDtTN}@YVu2BF zTX$k<48%Oj0}j`NY7P4DGgI(7Y5GQVfs;Sym%ts?HQ$;+L|G%FCKocfz8%k~NPV{M z4I?041^Y)-+ziwoN5~-oYHuem`kNIgW^EW(>z(7tCx_kT17=z;v9Jg*arEZ-2; z%j7oX*+lCc`dJ!nl!SLjh4Jvll$@d2ttFGXy4VH9-Ms_hs%A$1k}({qh&^90bra!f zhr5Eu2T5Y5zGD3`E~C>n0`U*_2qG z+o*B`MqbmXr}Cs1i#Voy23EDu86mpTA5-EK#STFnfc4RCIJQbD+h(S)ZunW-5^~!82!c=S{?v# z^pM9VxZ5?LE7?V2!+-3L+`_+bI$)ra9NN4dKG01He+6TMcUK@hMzO_xFw9DmYrjpx z;AQAJ9Zu~mL%yG|#l0)goE)(A9*WewNEz!s8%Ap5qh<1uIeuve^%E*#rvefS_Eaw6 zAVc9MUS>0ywUZDY4m?OWZwY?G>yvfA(Lv}YKYr$U@!yp5v>y*N8~VtHm>K(Qg!n{e z`-w2qaZAiL?Oq3J)@42fW1Ho4AOa@VFFuTB+6-nC&u{EiPlvl&MJ_JdWEeJ4V@#Lc^Y?ExBqAMS{3*ZR7#7yf0E2^5uN{q{e(KDMy?Z z4hM-iL(%;Cgtmz|8B)Xx+iny^>S0vazo?sbHmjh4I-4;ex*lifkFa=(uMVOc56wH_ zNWtz!!Bvq#LH>S32#q=7UOvfQjhT7i-}T8~Z*8?c{VH?gUhcsMcz3 zR30LUwtdh3EJcOF97$J}D3ai49pNw>1P0`8 zl;BctGD33qPOx=TC+KcMLf9NM2Iy|7;q3No;ChDbTE8f`lFdyzLU#5eLU#6`T`)2x zT#+IiD|RLtI;hcMa6FXZSrPS{55 z;~2V?!Yu>BXaYtLUELUW&asTlvz~6VCAgJgZBac<1f|2|0TJssSzIF}ymJE9btJYZ zTJL<4XyqF9k1rg{^?4<3PdB$_%aSeeB)p{R96Yqq|M>>n;TS~Rwi8iv-yU(vLT z;VU0Sl4OtgMrE@Xaw#GMK2nEj{@(k=hT+2odI~PtWqTN(j=uL8h2px*aeUnxd9?|u zNUFE(p0f>!tUFSj+cI+G#Aw%vXApU3OBSe0xgxi3Kj$S4a0prxG0U+L+uy1K-*wW%Y2~)iBJ511r8RvRSSsUBjELzRl52CfbFJq zIN99$0!If#>`(ihbEg!qHw8z?)$qO6BI3X@2Lk!znhk7Xu7bDdt48?tWPTI=9UvSrm@wDiy zSQ+R<(iN}-m&0Z2;^)CjP2@-``;MH#0VO7jpNBE{{j?JYDaWl}QJOL}F8cl?2jOrxQ^;HehS&vwYkqw;ZRp=)Vuv9}DUXaE6RcI$su-kh{$wKou zsj0dmfUb0`EE2a5#2UI-F2G23av#1UIqaS)9GmUWK$pX9#vrZik?L^=Gc)=?ZK<#( z))v>+>Rcz8v>C&YwQ%OA9EJ-XlvNMYT9hfHYYT&C4H3dkAyW(!^kNqRu;xS_BfgGd zgOtAvlJB5HPuwQXIf`D{L|&P9o~gj^Ttkm^plGDUk_Hq6tmP7?3QTjA=s$~6zAbMP24_18z9ZrnuUN2g4f-UqLf{Z%7Buu$QCY#n4p)=A0LKi`eVTE7Y>r5=edg!F zVAAbf_Q>T&UNOEDs$8QV6S|xx_~M0@hHO*U3%N!d7y2CDIY+gLc%B#?*R~Np2*nK; z2>U>|yN{sw{TAF&Y&VcKy9ytPc<+4f(pyoV72vUzqTFNgx$=sCGc+7 z^!5Y0&!SQUOmTCahkJJY6t2nosPKYAH>Y^Ko-W$l+C{aXd~~bTy+oSwHbUC}RG8iu zA&;lCEQ~RMCLOX0*;nflbpfWTu%5BA9{K5%A;Ya63v}0(X%kO)F`aYLSO*6Gx@|aC ziO#ubvu4Tk8DQ_J0ymMMn+CECQ`^r8?#qj)Kwc1BxVf4 z#7l)}y4?fu`EsR-wuN3I)XyOOLm?o2fAz+<^c)!qgASi=#U@sU^BJRbSDn}f)hg_J zY}=v`*_&2`$2<@U0=sIWlez)IDHLmTdqy4~Uv}659ZPc@?-9SpAlwS@1V{=EqBlMQ ztU2*51lOTx;2d@l6++Z7W$%qo5$k`=oLUnNbI^f39iKcqcSe%`A#2xCi6NABNGON^ zNXHjitb2h+G6Rgz-55?d@dyz>Q8O+n#p$h`}f;rn&TOM=IgqS{D<-ZA3ja54%HKCK9pDS8u`=~KC52RvDEw~ z@l@CRCizrqahqPoC%*I`kOjW|0X2ToF2Dj_@?OOP-b3Dh0G~UImuu4m9Mo*P@|WfaC0lM% ze&zR=h|(?g%RcA$9EDpQwsvlJ^qF$^?Pv_{v|u6I&QpPE3U9edK9Uq~y&(kUP7><( z{GYk;+Y?l}3b({)zsF~-Y(G|`SI}BhtF;-;WXeSS6@Tm73o#?hoyHG3@@!fhE>z3s zX;Q@pjYa@ZC21AR)#i&C)5!JxbfU=#3nsE*OxodE#J;qK$`l8H6)(r-(5D2iN3-O+ zJ0C|`EZx=Tsr87&;xJhnm(jyDF_|ZHpt(;H@}Mtt7z-cW70{kf9Z}t|{$61_`>Msa zxTmw#umeSDYK*&1b#b|I@wNKqZAp~Oll?7us?C*}L-9VbYvgiz)F;9|-*4>ar$Clm zbWrseas;ahF{dUBVGbo4E|`8oCvKK5HR#8JJKH<*q#>#2IhCw}849Mtw0UlE8)6Ik zw0cZYr=X~+i^LV95qI);A$+gmy?#uSbg(sDH*)~Xc?32tLH-+;>y+x2Ju9=i2>ElMWK zX2dzm2dG)Ghf-e{uB-VA<#xic88&aUPQj-Wn{WP}&BgwH1VF@e9y`a#D_u#pMw&JDb>>0c$-KKe_2Slw?IS|mvti+gQ#<_T{pFUvs68X zA}f~&P)Bbz*W9)%oZqmXahG3lDezZP1$Heoeg|o}M%S$Z>J8WLF8^&#_NAIY+^no( zW(TwP!;*k}AitDX%ifAy7u!zqoR7>gi&)Au_Fv4(^!a}mk;y7o7e;c2PNcED__trZ zKL5IX2(kJ*+{t}J+5#3fxQYyugHevs8~0hC8RFw#4NQYKePK%|zEe(V$8PPy_` zJR{UyOF`+#mM7~`aM_;hISx4wHPI&`;l;Cy=;6ar;GUc#a}AQiI17KO(`qhzw%H?4 z-uT=!1c`@TWRCGj%pqNedS%a%vQl^yj-Q=iO$TN|gcBy5G&yTuGjzx=^pE|8T4FfZ zfSK63NSfT4?)Q-)xPu$e9t0ViNSD(`JB3ieJ-$g}>d%qj29~2!L6Pnb+CR$gh;I#; z@3&jzYh2ZZJsdJRgYJ?o?o^UeOU5QB^s>q5N;`>UxVzC^<3!y!QWdn)fmzt819MeM3#oe|Pyms3Thwsp_14l|Rg}X>jnm8MK6!d)P z+G)UTW(fWS1MUO5W*N4?KZ72Rhf-Z8!0q-fxbr8$uW+)34I&Isq1Tp;>9r*rOw(uv zXh||fJPjHX#a@U&_A90Pv&Yz&0`1UW0TW{wO|P8bmbn>Y7^Ax#S>7%judJ)y454%c zuN<#rijKujZ`U99De#=T70Fy`C4a#Vcb;KA;>!!Qhp_hWw)PAc4qpt+&R{s=a zQ=Ugmg>|D-NiFNAR3(WF#fS{a*4Q~X@&s$G1roN|YlY#E*jmYIQ(*Mz@Mr@IMbelr_7Ll`C%8z0T3yn=$^gIkq6-WlM|Vu zB%B4nkd(4`Ll;i$ZJi<(IAZ9~HUnr{aZd9v@la>}YeJ2j+@L^CWZC zXWr*##&8Lq;YuviL0M|yfWu}b9X%G@k=(iw*3p%lw!XJGr|R`S;?x5pJ8*E`r#|L{ z^rsC0GBIOFh->e-RG-0>p_DJsVKsZ0ecJ#xw>aS{PX=TkKQ;25)zL3!Q}5?9-eETr zxf^rfJ9=rvOv`7vMw@a1ZS8Y{4MF1Z6|?tL-%6Hd*FyPHdfD33DSpAW)Z)8ifhO9k zYAKOfL4}6=Gs@!+1%lCV%OxG(NUbstqf<0XN-vVVu7eH-g$C5Q0cADS-nY`b^l7su zEUo1i2VS!^xBIrBnJmc;LwE98Rq-|U@Nfy~g59pw3VdrdT;*}xp?cnk#0At_J+Zn? zg(~s>77SYq7^Dfs;ub2O{`=`5%ITnTi5D;r&Gvm?vAT7Iteip80`QuJdRPD@@-Ex+w zE3h*MKhU&v#`~TTl(P?luxPA$rC^VkXr}3yF7@`3uT*^3I)^8w&O0eP`{?2uxJz~p z=ibnxxdsI9n=OptQu$(bP+I16UOS7b`YyTav<(vyi5yZ;C^4|t2Epzw9YV)^PySEg z^na6#iT{5vY!i1Q6MN@xXDFwC0l`giL+<9kD=*A%S9G5L-3??sloX`@-G)}=KX3c* zKu@-^)Hl}ylP8r|QP4vLQC>k;(83=QGEBt#M=-s}2xYz8KyiqKlC&bYsdnq#N~^;{ z3;=iei{i1vLNi}ke{*vr^*-C_%B?3ex2OB>5Bf+OtS#~JwEo5@EDB`&F-XH^IH$DK z8}*PN3n&;Q8cFqpxe#(9BMn%&p}2%vqCG63)BzhIrsvj6Op){K_UYbcto4?zEa2NQo{(Klhg>FSQ`pEJ0Gi|G_L3u+h+%qxY$JC3 z!Zrf<)-$*RjoE{t0A&^@f%Fmo#9ByA7OM2SxY|qjbgVYxJ_T3lT1$H4vr8em41@IG z-}I~n+?t}Mgg+%gO|$;$j8R)8{)G55xRxUshL)DHI98J3*-EJP1Q=0bg;Diyd# zV4&!RJ|YYr#uekFCENAk2t5R>C(#+Iv;2L)R)H;y%xR|Z<}+*+aYDG%oQ*`R zE+;g{%^T&Oa^{01rP9~q8O6gk$?#`*i{&2F(G;otxjB$0wjTP<+eaP&eW6OEAu5IC z&jdOF3D!fn8NeiNBHXEOCEfi4k{Nh?JWO?V`;;(7hJ+iTrINE7qR#Ud;S6t6+_h;c zE`&u4NrF2o=HHerM{b#_6I{bHFpf;POI>lY12;>Q9&aCwS`FM;OG(v4Nxc4g9L|xha|58f+ z_@ViYsekW}|GK^vdH>B@($d)QUwt9@b&B~-zB!{2-#d%t|NgUpp@FTjovn$nke#iq ziP1myrjWIXfvt!n&R7)Dgth5;~$ZD|KOSUTy z@~rXKc8^$OH+uJ<_~0{X4p26pSDGpgss5M!HGfW^*g6096L2m>Kp2NKuU+^nzj@mk+{TGC@QZ7FKy-9B8)Kbb$~sBM^WWG&hZ zDocJFHyl%wW{*CqOeHo)aD6%{6_tz0TrBb$Zc@Zo!xlM`IDp)R_ul&a!jZ#Wn?thT zzGW>h&1M@Mzm8O=#6N5ob12@r9ajmN3aVzeeB+DHTjK*T_tKb9#jHrBdF;f3h;2JR z`ZN6{_0UB@PP;mAlqE=WY9G~ZQAd~ErG_bFw>7{d2JddJjk1GXq|qLM^FITEvg&Rp zU)iEh0D|%3v1c=}w~ZZnrqvSh?Z^f3za5BLhPDxyY8a3YLAN!W?5Evitu2V{A*R2J zF;st1JvhTeq4=D!MP&D^WdI|4ZdOGN26G@!nELX#2>yczs>n!31ruJ%~HLf3+I zL^5p{5^pLmZi*7w8WC$T7X^q1i968%(~L-B5{vc75(xK&d1w{ye0l+1VW-=Z?B^Ey zt3X5+j@o#dT`nxsRC;VJr-#8ZrIJ!Hk_J?Ltr`F(Tbe`M6}Si!WxqK@KISeg|LB^4 zEaR931u{;eK{!ULnqQ#@dPPT`;QTa090>FIF!j)HwgCIrwbmAHdX{oTg|}SB|Ey8O zDQo0p^y6RHj(&Lom7w2m#KrHu`_F90f7|2&PT!-L|FK&|4J@opjQ`~g7_Fr952^#t zLW*q%Ku}W>NkpW$QAC}pA7)rsA)w^$=XwxE;>MLsn{kKM^T6)RT`^0-X$Rjpdq?C@ ztl{e6_E@=}>dEVcjKW~y2e6XoD5_FxtbLsu^*V{u>K&{Qcp$KlDV2 z_css2oW@r2QOa^~hY;tN%%P8Z0JoBF-KUaQTHVxvMe>42&kSVKm+L(MTVHOs$Xd_x zs0MUK9r3Q z%F|k2;WI5<)qNfuf<=ajj(E`gD30b8cav2i2A}xnuroZR;#JkNQgH(KcuHw+QP&?f zCckhq1$q5JPKC5zndj#Ys$^&ksFyQj)a~)u_WxEOSBh%FI80CF{xfT4!xE4z_AMU} z{SK*rCWQZcIQ<_#;P04{w{|hJ_z(BaXoU&c{_ocIKxG7-GCp=HfCgZ#Z6uwvTcOYx z4&x?-br#1M?1A~hg5mp%z$8nxKw@ri=x}qB<79K?-{ka8jkp(FWnAWn%tR&cjB^rc zgP*Iy+MDxG#AO{ee$skn7)nSU{wdnRcmXNKOar7!Tf$KzkP#5MZsfx463Fk_l*Q6_hl3!W+FG;`0=TWY5o1vPslCrye(xY)V;j>c`> zIKK>R9)g=5$v8vXX zN|y>LNdbaRZO^E!wa;0BWvjn%*Fw`_tg^9MrvSu)b8R}eP5#fTQTkVJ74~~ID85(Y zp9S^*wi<#4)&{mlCf^9dw>`7jf2it;73yRM=n=c9^Yg(ZA>z`~4EhY=&wfxTR{rG2 zO4lBVz(wXFftU1+^7lvBEtIDNLP90Tsv+K>U05maIfRuI%?cS>e9F zN{vkH)-kISZx|H9oS`OcD3Nci4W)-xE^4E73cvZtWj-OuYD9vuu5mt`@`Un>`$%wm z8p#J%Iu_I|4=P#x3oDJ+nylcn{_U7}mj0j&xd7Olq9XGP8raVCFewJCPvJG59h0@* z_k1~r{i4rn5azZ-n zGZz=N*{*J;>Dj@{kr?}PFt|zX^q322?)(VJo91egxhFo`&+px@$2&9EKUTx3ftU^0e-Vdy?R4t72e3yN3Ek`OPz8R^$p=(O7M{9G1X+Go13z_QQ~Dwk}aC&rZk8( zYA-W8uBYY9y(KjomaUiBP&TJzTq6A>qclu!Xxw|jsO>187w@sa%&5FeQUz$~h8%c#B!85@)xt@X_^SJUJZ-3(U zIKTl|LL?MctD(w!c{yQXj=gSSqBrW73z)*l$?2GTxv-BY+xS)xvh;LbdP8Vbk?2-C zgi$GM1b({gmiSzMLnXL!>1uPz*m|2FqiNc6%m`sJMfz!^CzYLr1OyZui!!53ext7j z_1STjAfPn2PlL2hvA{H-2t3N$RM?1nI*Kn|b~F^l}#}#JX5OXv(R%~-g=%)|4ZVm)zVxJe}&j4w6`q1Mfo!B%CUQV zuYLfC(16Dn34??}JWQUHBtN{Bf-qPDinBzWFWEeM$N~t509s5C8|!MeqC+A8NJ$Vq zl|+3syq5IPL8G@M^jZms3;!CFR>+T=LB!ix(V|eX^m1-tCOc>TV!(nazvw;dGS0O{ z$VlpZ98QI`kC>yhC%^3(O0L}A1I;1BR6=h;-l~%kcpcg?btA&|Fvh$gW>GSInF%!7B+=*?+LU8%w*2pa`(Z}3R zjSrzRlZots>jm6PL+aYcW*_i96j#ey|D7LN^3~{CH?Urc0+2X$;k3U4O+YTMFpI}| z-3r=-71UKXr3+bV_IgB)cvWNezJD@Utp< z+pa9LYtf@y>P+Fc)qQ{-H$QD0UutmMNh9_8$Rpi?wGNN*BK-JGyGLSQprSU8ob3!|WXxU8|wKxV;*k{UA*UiR@t(xFO*JhpoJk?A!ee+5=FY zSoyiAJkk3?QG3Ku2TED}Hd(`|9|)i5D8lwBnA0dj9Ge4RAJAw$dqln?s9*fxe)rs; z5UHD4eo>-tSHjd*KZUJ9gqQk||H0*7_4o9|BKeXH3V(;#w=u%Sxxv#d(vE8_!CbPn z)Gl11bq`l1`RIq_l0R7-bY!6|!13C&)HJ?eXj#XY8#v{$wWHH0bMbmFKPNTvi%-;T z_Wh7BwZ{?AN)}lQl&YZrgkXWmipcuJ*C2U?=ncOiE5MJugnK7H(m7Cxn-DQQK z3y!Tcq12AY8XVpdBdHFgzfPFFMF!MdaEI>a9|E+W3UIqi_Rg`p^YFL+ruatD%CYMoq(v;r9TK)}p zB9w20Y=)t!_aZh5!;>;HG%~LoIi|IShsKF4_Xc1`11(1R$7qrjYF zi09@)U%aqeKrk*r@xep3K!@#4ljg9_og;ZhB!$(m7;pck?t>eldCr0$`{ zeAS^cx1su-x`J_A*idh5gT#WeiM`_3PMd1+k?8Q`Xd9`ar=DTN$ho+3&O+YgyKNh7 zP-q- zG@|bCb9!udm)8?6*co_jwuLgpT3v?-%?^qg^Y z`d&&+PRg0`DlbR}*!o5F@nNLzn&m3)a6)((gwUC-R#+d7BJxr5QTs`rwh}HS5tbQIjIz$yjltR5lke} zYccy{XUS@HLNayg0{6N)ii@lO?$i=3zq8@OX%juwer_W1*$oyD?+q5EGm|{h{}oZT zpcEfYEk0_9ttc}R^=_;)bKi`r9c8OB=LJs2!r8K<3YXD!5Yd>a=a(2hR&7?9(C3+T zd9OS83^daOf8UtF<#pJ<`Kcv1d}d@yWfC?1g=CCTBIR;inN?D*zA=2fzErYgpPPp4yp*&<}Sg)|1n>KiDoxv!%$6hnK92Mi*ap9UkiVQG1&`y** zq539&H2IaGc$xZ{oGMY1EY8OLt$Nu89Ns+d+Pc3OFC5Cv;I6SPC2l3m$b9@o#1H8u z_Kuv*88}&P_Xy*3z~OMo*|=Hkg1+YVc6n^s>nUcvK4}H>jfw4*+Wl#8Z%*3}w4TWh zJj9CHlL7QdrUQL+lXq}~yW;*rGi9$%w{LffvG%|&-7zzV? z!T5uTiuuYjBH#LySsYT!Jki184+E^8b z&GvteU@rkq8x4R<#|HC}j%6V3Gt>lKdHsvs4h_bprVXqH9EX(euH|=mfiT2PINvENZkSx#a}yWowEfvi!&wfJDiWZd z;zn+Dr`wBpqnY5>4q_HPB+u@^at$_O z-G4PBnt9srIZ;^MrM}@rbc%FySog%dS-H1T$|I(5s<3miSQKko=))(26t5d9-Ee*s z_YIMCE%Jpz)by<+y(j1%b_nchKkZgioHPi>Z;v;VC4?{nw#+5d11eKPa5?Ko`X< z{TeVGeJ6u|z1_&(W#Qn7=Ww`zIoEY2gRe*Mj7w;n6mBoY);+!c0fF?@CTf%8Wa*Su zy)&G#Z#h=b?hDU_zg6P7s$yM{O82zVjD)U_SL#+{Z@L5hcmKuC^o?(Ix~w9|eo5G6 z-GPNn-J$chMwdfKnh-RUG$)$dQh6(@3wHoF{wtVD&GOk<YZZK zRAT_vLq!H&fT*hgt79!%w;BLlhXz*w{4PuiUk9u;1dp-P%)G1*09FxOQ?*B; z2!AiO;G?{it-GB)0eVMLwu+F;&JQeOHz&2>0koRuMiH9iO0h+I2V=SH2BlKv071JI zf7F21a9`GyPN+yHaz;Gj8^QdG))0|v2=OUm0rd|or^q1byu4;n{zDVfVEd&ep)mb{^vwZ)X~mH+Rn(p+0K#VKRzXF?OmL|8y+VADF94X-BJ369KN1R6N6g~Nj{Wo zkp%9gkYT=l(3s1c(?eosMwq*xEF((09+(QG^SWAdHO2C}zO9Ge?Mthy%idOJTl|gv z!phF^LNS5_TAwt&ZZn(Vd48XEo00kYI7y}bVRlo5wUuUn010q7XY?C%w+SzY~PB>5=G_0BuY8G8nB|w0X0y#Aa)>_v1=G{<^ko zw~d7Y^;r5NX_Q)7IMV<8Nut}{L5=ajhpkqfaEos>O#qHABuY@+(ya-;Yk2VO?I zKO$4}sR_-d=U|fbqPI_uHH!qvyHduJf5wxVCh5UJ>2uZ#`*j#jqSN@P z_WeD2_CHAla+p({p+b>4gnGI)#m|>%X|u`YsAI=VnW;xk&`Kx$mA4f_S{1aL5}S*y zz@RKQ>7A_@eSHm4chj3v=F7c^HhlN_raQ+w1A{nT7NW0#Y1yA1R$?ZrgHc-%qdN3nLUKPWgozf5p5=5BD zU)xsF$1+KEipUYKirOqq9?EflD{0})3Ur4;6U0=W4v3(M%@r1WV7a$rK4=Je z5~ur-5KhAxDKoUm)b}xQV)|27qO6Rmx^qm;0gVx`DX6DZ_(W1=31$UzNN5wIlQvUM(sU@0MiJftIE6KB|u#^K0k1KFau(i#v^k;kT^`77_)^*8ozPVduIo2Xt@hh{Z+|RGiimqh% zyLj8inb#y1_iU4!+mM2mTA8FPQc206%QRA2GigIEPy&BtSq|W|9dgb`ulWD)o|fdo z@|VzULGI>mkBdJ8@7~^U1)2ihp7ua7-^M&aAvE}ZVtRs6zJSxLen7*2#Rbk&vj^s{ z*xy1$Lr>``(hvL+uZ&xZF?EHcy`b-$j07wL5u69*y6lk*mBqO`W(md($Ndl|7vYCY zB@~Aiuq2wf*CBl2G>(?@K0LOc?r1F?c-;5OvbAyi3^@i93$;oFOoOeFgPVm;j>zDe zs|aPXw}z**@IFUg&#rr#qvT+hjw)XJ$T_0Y8sk?JuL+TOG4#d|4tlds#2oN)L1kwL zObNbZ1>eF&h5>^H6U|VA?Jip=218lJ(WFP*{XnYMW;u#SEat;83HB9k2{27o6iba5z@^kYgPF0Fs>I{A%k=naW*5G%Z zeU0Fr9nnb)x;e&XO-cIW}T(?H%W&v?`G8EzqsriQYiLJjA_v zN{K$F?h2)X> zi*?dT*y!2Qq3#h4BUK|+Rvs0!tXwKxmH_f1w*vG9c^kV}X?yYwvQ%T=i=(~L#ghfgN35j}VVl=-?9a)-T(27#x||_8mHVui6PM22Axd|Jt-lEv z3%3Niol$Ds?kad*Q-LcyFUb&gWxv@}?o%LoR53n8NBlf*njv~r#QfAE+-|&APxP35ZG?^L`JAbhO^erp){ZQgqRKf2yAxVI<#_RKG~ZQFKEY}>YN z+qP}n$%((QZRf;xZlCz)!tRTo@cF(l21gu%EM39n=;kRhX^Z=%Uhrr6KD2<;-ysgCBqmGRKTcNuQ%YWvu-1sE{0 ztNH0W3GQT8(8VxXhNeE_#McwA9pqShy^auZzsJh*+GtbAx-Kk1^>V(5zHp z{ykuv3BM+R=o5qEDr)H+iy}W+@?4NEAvqP@#l*FQn6g+?Xpm|NqXz|KW10t4Xx>mz z-ixm97NNRwr{&R6hmI&pYFYBO@|7n=K5)mwBJwP%NsZ{R1?i9VTCPC}(cQe>-DOK8 zXB!(*BV;~4s!|O1sR(;H`+X;U@2+$dG*2aSve-U}g)=+(hc-QuI-PlQrN)tiO53!s zttjDzUB%CDWNc5r7IY+n$=6#^mh%Cm)wKRb?kfl?O&l-ITpzm|lkz(%c8J zr4U~cwfmJG< zDKCfIkD!Q{T>Nn7smY9Wt}dvRKF?2;4)o-obGw(!#Joarh?;3ldX{{LJ27#vTKbm) z#iU4{Tyi|TK1njOhFwMxr>x2>M&@C{(IAcfS|W)4ZjuNJ=2{k~S^&@F73PJU>G5);pxn}}p{=Ve zv7vF1JhC?N%4<_lG<}Ds7clAjim|mnl-m(a)Y9A8>gg$7(b{P%Iwl2OtRAYhQl}}4 z^^^lEZBj{Z{%Vp5>a#%k`v!X7)zEZDZNNa*@e&FYXZp&0L-@h31&{K{qX}R@XJl`u zzq+>5$iCGUG%3`UU9wI=*A!HEC(@bv0+2F=0w0W|Xmd=QS#_}^%K#;b3c@nhkY9>$ zWl@OR=3Ls;UW$ss)`e12)>UiaCFiKSE)PpTb))4?t0m%zfEVjn7UNzJ$%ZCJ1s^8o zAu#`iqj?>zvZgX*O_4g`yP}-`V>!^N zt>#TzYFv6iivaXnUlI>j(MlwMFLK%YdM`xM7L!E7$X>^~Jk0#r&rN$mr!JF{An|5Z zz`|FPphN4G5Zwo6=e{p3KB%j#xUQ_w@gsKh;Z<<(yF^5zMvx{)+xb*mp>g37JY@vn zn4Q3=#*Ebpl%3kyF-<}D(Iwi=K0c8p!4`l`fzrgw8(-|oM@(G`QV)IGF)iq7*PLzI zQS)kW*&M)CJBQxY3ydtuDvPNcTu414IW7-n@bFHhNYXIk;;+*1)Nv=`(S!v{`>l6s zs#*y%n(kWnxlH{nE=b9A^=aqSb7c8`t**+0Ztg0^C9C8e9a9Ml$8Za296AG(z*S5A z!g8X>lrDXrdvsOesaiY?q0R){((+I^+)C)gZDljKqAnDU4XAnct6;Oy^0HYBN7yK2 ziW5E_ri5(XcSn$DTAnhdFmAXI`TeB#6u^+iet;Z&`2DlPe40s_$7s{1b{f3VWzG6W zu8W^}rRkncKS$;!Z#egOA+TNO(^LsUinZVeDzRnR=$AXHb0G?M5Kp_~DoV(mGz^f4qmpUO7%f?T_vYhkK=a$lVZf&!b{$#TR zB-@RSgzuf!&BN6dL`#!EDD)LNNEZy^xe$zG6nFy}+YOBuNXG&=E>BXb9S$|vv_*!n zT;L402!r4&4V318!S5s8)xp@J1&VIQhSw*DxNvx< z7OlQ>dI}WO6~NXNW>dCxAF{)wYy81nHt9$dY$B$3V)x#xCq}p@hQKGr(AZ2MlZw%1 zeys*F*}jbr)W3mUJLbK4v97q=qC!U zcnka;xhJMi>Qu&l$aOTdJNM}C>yirp^Jl6XWQw7 z!f;v^je1(ixkm%EfG~=GJqj|3W8BpY;Zg}WAJA+SINCCqzqvGg#&SDXecirMe3UC3 z-ZPfrPn>Vq*6CW_pEp0RyB}9V(T|d`x4wNkRi%bA*;1zdlchFBmFKl|o|<2Epjw4F z*A1)ReAKEya&0?6EX((XEYFc1pB?AotX>GN*bq3%(}wA&#SGI{TS0dn<5wd1FMjgIrlB+$p(eIaxZ&5sX|fCH~f;Lot~d}fl0?# zw-hEp-3}z6FIUqeA^FebO~Jb&y?&>)z635DlkeKG0EVA3D0yzv=g6 zh41W|6sH*hDksJkM&1}NUo_KAILEI|Dte-Y+%2}}+=BW9cf zDvbl`91;@zGRk~GcSne};>H{h;GM^ictt()j$fobko^bZ@A&gZPd&s&_boFc^5-l4 ziCjI@(D%4BLslo&9~QzeO!4%{-5KU5^ivsg_(e+Dh~WhK4C7`F z>uAoH`N3*vr?|QRA)VM?Bz0}T$JG~+m%IH^l!!;58qAm6AB z`~PI9fIEP17O+P~8fXSv$4hy9;A{atuSwv%6qHX^olahEr}T15avwhkBSD$wFKMuP zPmW*(LjV3p;J8ZBbHQ@`n$t&DfdS`?8GahIiE8-EL$t0|&(%mkG5gQ1B~;U(N@<&O zR;5&p6g_{X?I!*dcO)rsfx23D)vm<4ec3d(ZKi+gvMEmQ)E?l6@nNC6B3g?b^sS<6 z?pe{vQ2^JxK6N>}`K_7mI=ei>8#~cjh03U_MB^su`uMaV$O@xn4L(oov-@G)VHpZi zZtczJ7t>ZhC;G5b$rZ(%r;*tzYfVRC1ryVn)wTe6r++|qaR~-2{&cesvSG%=kCE=- z#NHhf5CpoHz%(T-7?W~`Nkd^w?0gKH8IZ{gWiA0pV*o^Ke>KXV|`<2gJofx`rUw@(fZy)vVt&grNCoDrvX3CY0%qaD|<;?{D1 zk%e59D1S@?(I}-HI-U6ur7PE`v*&com6CRtf5(SXdOW3+elKz-+rGZGHN%C*uQumf zGH6=VtV)KzG2g!d`*^M6{&mddQYjKWUBDvV?Sq_(n*FViW3u)&7I} zc~TA*KnD7>dJF#1e*Divot~ngUy!~oY2Jygvm?w$hoRM}b}9wOq-{$g&W>2VeH`mv z*D~eiSZcV|ZDszhBG=U=(^9xQWyUZb)y7HF9PB^$R;Y0__Pv}16JY&fpGld$Zpvd` zl-FxwPQQGvrJzF-9u>KSHXk^X)Hn3Mtli)XP6bP!wqsKojLS9H5)btgwwSNWU?;R-rK#Zh$<$(|4u-?J;Ie9ri0ktcclFf%v*Bcp0)Ns9lfw!c z=uBJh``64g!k_;TDZ)0AomSOG3@=_$BuqljH=6mni-a?b-g`^e&E9(gDx3#0NSb z;C!@ax$}*(^W%&~B0zSQp9<~CkHPd|!`P|8Jl!CEvqlyZ9jeH0BsU&t3EW%`XoMH@ z1jD5$rDO?I&M+?gZfOe`IsjOT4Q$G;<%q7eteE_#XuMxI>i_JZZw6aE0bDa0WxzIO zP&yh0IDnoUP-R1xo61ESy4*T0DAaEeR7xI^_y(H~N*;faz6DHT($zP>dZQ&Dv#F8P zH)Fq{olM|p05Ei-Ke128?J#^?f=?iPqG3wZ41|RW6auxoMX|{ zbg8kk4A~G}_~PJW^BU!dJbmVR`zaePpts+V`s|tnm*8v2s3W{&wDauE{>t?!sP-qD zo}qF1Fbq;U{g{VkykI5p|LOFJNbm`HyG$R~A0IB~l;#(vNJVnzY*;M3L#sK24u?_a zl9I`-HSxf)CRvyUUjAE1El@vgI&Ure7|GQ&4{K%R5}Wyy3+qnZ(-|eSj^I?kjsARL zlKDs( zMkYLhq70b`zC~mTv=9mcy(fkWDZmUfAtVtdpOFF8p}7cJXzfz1tgo_G9EPAQ67xa5 zdfvW%ZrrT%wQ29(ytdQU-n@ElwXXik|Jd$)m^PU^`#yS^O#jIBzTx_L=s(TzzQO3b zf0j0nw1|ZCtVs9E6~#ICf4#%;`%EL~f7rY8_WKMZ_?e9Vd6?6F6vz0Q5MF<@_UpMS zbHCL_>R|~sb<{=l~jCzdm-9K_Z;EX7@{rBXOyXt zM@NrHvvw9rt344Pty458{1miRH2+H}Msu%sizH9)&`|I*e@H7#8~kqTEBwALT#?P? z3lixr$YD!t)Zk@A-^GQL2elOew>fcjMR09#)!pc~t0?Ym?%f^5g#uh}EX@~kGkW(H z)Zn4;@B|rm9~3*-j(vMHm>QkV7^oyTYQhA>h#M7pP%@KKy4w@3a3RHodjSu12Rlyf zKyQ8p^Vtet)e778_HGl3KdxseU@qWoTWdbH6<|RrK9Cn&;8@(~gTRJDS&F}8ox~MB z*R@{Z+43IJ?MXhm+BamXaI1%o3f++l##K#fq1&RH=%Zjk{oRh6(`c|ZnvFAP5ojQR zl@t^=;Y8fQjR7f0bVBLr;HoiGj}f#nEhMtG@%0T=V&%PAi8)i89xRpQf?sxGe5J#Zz2F4Dj} z&A4!YFd8aUfcgE9MExg4D0zuHjRiNLu~%obTiC_O zjDUY2R;4?bd&t6r!sYt3f|76d;`mBu8HRtI(YcLgX>vA?8Cv2;j@egdAEn?kIo2(d z5L&OHZvFi)j~|qziaBe=&jem7z~1FZ0C|L?RzQwqQ5+QK4!&BLl-S!-^7C%s^jHCl zp&arSYP^IEPsS+Ja9|4K|LQ}MRH!fD&*VE!1D*_NeEU4GM9Q&idL4M7IY?5L(OA`& z^pn|49Pv2T!h;QYS4NT_nEzC3Pc+0s(#J5^Vl~o+P+HegN2dzcBg<5dWP37mos@{r zj--i!psSh9BAw+8^dTTZ2SVUfmBULYD&Sc&5X3t1BH7JUY_lz_QCbEr|617z*~G_- z7v1eiY_2(&fEKqf&#V?816wl&BMF|$!$cRvAzX-^2qoccap2>EUkn?07*o9^RR44H zFOdhArDYSmPa4sQ9govA=AuyCP_^gxf>@C1>9wk^@#Go$5Ai5Y9Qj{X@X0WzlUlF& zRcx4n>}YAPl$u#!#iONT4b1`@lGu~eCF9U=D6m}`ow-J53Y~bn82OZz?lSdq0cVuj zX9&uLQqZPeYo560RGtGVp<;b1i{kUJ)nlt-OK`SjJh(NeyTRMG_ouOBZiD6r? z-OG~U>R|z?Ymyqt^&->?;Vs{aKBjj-@$4M$L&_E%H@UeZ=yoG?O>F z=h4(_M|$ksG2P-JsBo~iqSs>{HJ_(A zO7}hjfpmtg?wLh(4x8#Zb^>MPFSz$Ss=o6ud4Fj?)`hjONaDu?7(!3 zM5>33$_-#}^E{V*zL9+=GtwnKZ4m6yD3FqPG7yTn&oPXd^0*hVlup|2J(LQ`F5o)X zq%SsB=0z1d1{{po$JN4IA1=a3S)TZ^GxFo(3WL>7r^MVikxsSO@U>Ox!ZPvT2X=~h z{nmiXqn^hO2Km-vNl} z<6;g!58An{nAg|x1WDcVG|$iRV@80xJ&ecyHZtt51X(&lh%_%QkzJemU|9USJSRwL zZ!bLA**Ou6Vdof-iTZ4^&Qe><-Ght~dplBMgcVZ6Q5JF4+_!v!*kgz%J zLs~zJztx*ZHd68k7ncM`!>i$VT+4lL69hI6kGJ|HYOr4UBJ3l@SIGLAl|3EO2)%Wy zdn-g!jvsXvgmSLR-Dr4xg|}kJ+DERpjfz>GUTkA#(NJdU>1oD{N`j@iVi zbop_`kg?UM;qd$YlXQ}g@FiB8;3+rhw0P0!K2p+bZ%0dp)c$(m2l9V%%RMJa0;Di< ziDs#6hpAHCa)yq-0LRuXl@x}6xLseeH*h>M^$AC(qSg(28d)}F=*e?pjcaN;E~#d{ zvdck?acv$+F0f7y8Ks@d4bqCtVf|Y#N(9YDXF%m$>yS;DU}Pq-%ez$uVj|G>0B zEHW25-w+!hzg)9-#h!<;8vM;F_lhTMuM^bsMP>SOY`GrIfEbvI)(|kOg`!n4 zhHpM8u*o^gWQz+AHDbxm8J&MX z^W+QZ1>iu+6WM09WM-DhrBf$_M5eC*M@CTp^-j5X~ir<=1()OkF_(gd8#m}#%)(8qdADItVwY?fSWo5m1dQ!0Amg74?jp-_+zQ~sA6E! zi$*RpK#2CdyV*Fn6R~If(Fsmn4v-4_6zNG@+E6H+q-|Z(dAB!QYi}H`*S2!#V^4~2 zV0C8D&tjR&4`yT&zT=m*?=>2yY9`Fxy)j>-0rN#Jw43Qe+~{C9HO=DDV7!5y_79x# zW|N&jpp$ZHNrGUmYoNm$lxL=22!7S415q9RV(h$JJ1(>M z>J+u^TzOAe@rqpFW|6fvv+ZxP$gXVl{bkzMwoFS{b>HAt`57y+30HGhskYLnqFE03 zT-pu3iO&{3BcQjUXQLsZQb@z+mZW^)hDC=6PKM^HL1NS* z<69wdxm4b2QZIOg)NBuR+Ezb1X2GanVH4&YW1A$1fggC3;@CPRQgk z_pSwvmpU(s%2SHSTdiCx*0}b-SWhl!WQXTde=Ze9$cMKx->Ut$bFv`ih|d-oy7aqB zZ$(GR!)lLVwIg??f)}XITNS40rc!>GLwwu$qMLstl9xB4

p?9?j-;qd_@Iq|IAN zw^K%I=SP5E4(*#6(p+w&4P^s|Zu493jm6$n_6qLM!|Qn~QrOX%&_4H7aHvY+P+qmv za-r^&f2Bc?Px?{Wh+;K-B}*a6qLObha^0xVs40Fk>NP#Q{nv3N7snb}q}WWZ@L*sfZCM&4UAduFj&UsU_{gJXLh=t^b~LdTfJ7Nd$iYAL%o ziz-{rGQ^oO`1B&F3~p&EW~nM>=__^)sCIs|r z5jRpNni6#+^HVd=atlnJ8r{_97^H#};{Ntq6grklvE;JwSwu8bV*& zbWy2SR?L;3oqvFSwhY)uxhL}p&@|Pa_I6a3Tvw!Kb`SNQ@Sa1ww|jpW=0XH_Z` z*0$Q635dR$xM&Dy3b=$%aHr@TM!JvcwutM<1`P96z~`5c9r$U{;io{RXScC6#$J41 z6h$vh%tkXMTdXJics>H#*|^PphaH9gg&aOo;8%R(+H7Z1uTdlU6fx_v$!0@rliAPgcR& z+}e`QU($%o@Thyz~{FBs; zGKU|>ji%(Ps;~Tn#0b#EFe8~>0J78_{?k$KBiEo#CSA`Y{ip>0V3lxUl#Ely$w?|< zo=8ABi*nqr0}=kr7LZ+;5BRiYW)1&Btv6(OgJn;gRnC0{UXEr^s(+1wPxcytJe{d9 zGf`n-uEN}3sZK)r2lvGGRa-Ba>y`7JbUGpN!Ass3r}`d7=9#mRl*~^etUR}SfsiJt z`{~N8yXs!}&---lNmEk*)R&&6?lIo~Kz#1$(E04W=kF8P)-Ll|Q~AGlFqd9WcwK#= zt)@DLf5440c=gS%B@ISN^fKL1QTp0(nVRoWk7%`oo}ylXYGv}@x}(y!3H)2yH|o!i zC>K0fmb^KZB zlg>Fr+PgB+ECgR5U&TUANPIe*%@}!wVdy_wl2$UO-t1H8$zvJDj$GQ=Q)Tw^?Z<)h zl0PBE@>PYa=RAP9Q^Lc{bam8)Dv}rFxc-CNtK=n@9B#r+%p^@e3Wolh_=F}T zu|pp#cJw)~;wY~e(U$ewMN_d@vMTyjJw15j_A-&w_&(`fReiDV)5 zTCzClw;Bg;|ETfPK6c%MY~oBf$&Fp6m=TR6GL59t6m!~Q&rv5WJDoq)v1lzL9dpQ7 z!5e{s@BCjZcmCy9X*h|2x?a7!_@(q~2#*+x|5U1$KJch%c&uwYE#H%glfFyL>8-hqsrXqXtv9(7P9MxG zgvr`en-;}B#&kgkN?Im0JY%|N^r_P@EG7>K=lW=6yFv{4w%{Vc)ob5i0J=8g+1{2x z*Bmpo)g^SUsN9hm49naB%L+VU9dq@LFHt+NzVYd^XkBc-M4rI@@!X35-a^b=hXS0$ z?O>%jX_y#U6oAyXWG} zHsEJtYx=lNPXwIdw-W{WN&A003&fK4(@btv%k&oR^tl)FgHl>;n4H=9kf>h)uAFQD z8lUTU8Kk$eD6?kDD|v=dcF;9MU>lxPod2|pE(_F*Gr(hzCX4Lmacu+(Y*PbQQi(qO zi-vw8pj*(JsbzUSmC5>2LKs0DFmB_3?IEEY$&igWsub3OT1Aa*=Or7Ng_S;82Rp{q zVhA2Swg{k)D~kY?MOBqW@0CTVm6Ph>)4?&2T(OQvhpOWvlyq!HOJ>80W8@a?j%>Q- zm!+GrzK;=&yF&9!vhz%>IqNR^VaK0Xy@hGc8o5j-ABkCDGm70)d@YLtrfctu?c4DQ zs~zwo2SCtQPifnRec(*`$EsE5`810ZjodlXv6W@kRyM84E&qLB=CAR9M?1cr)1G++ zcIi(8N$!2Bh%_hKtjq~OT5u>P-YI6;ZpFx6Gg__FEgAU85R9D`%=`%9jp4BEiRnUO zyAoNXROSJ8v$OiERk>9f5h{9S6!|-H3iB-U^7-Qm`tdAo{><%4!o+&hRcn?ys#58| zD{!|S^hx%sSj+?|eS7zh-H&t}GD7u<%py7)!`9jkA zL5m(y#z7)1ijI;X8`oP(8r#fmu~}SWyCB&nlrGY1Pn8FoRoKVL)$H(|r_z+VK)0W+@w2ypKdk#{CxR`4T)d#KpF&T9E<>e5`#QA zO0b8UK7`nOOSAW380salL3W=#Bg)kIqB~dTa;pdf$P66GGSnPUsMJp7-z&zA451@Aq^&&u8^| z!e5TD{1d13j}!f!@ms$;?*emPyD|7bhhl#oieT#}GZ9Q55^eaO4^Tdp*~O3k6JLiM z7aJE#jumF_vdOXACzjfOE>iN?A|4{?0VQPag@h8WJ0r=aU4Kl4Y2GFti`Mcy2j(Ry zcQ##=Xa6!yrpWdIMgrL~D$quSe2fg?SQ7hd8yh(O{zt^%kFRq_ZBH$Wmz(vQCY|i` zF&kdBIs|bl@aTqvwt*lgb`01M(SM2*3TyaKQ~xY%YoSIrKIdJXlhKdb-isSW1Dkn( z=QRpS>6eh#C=+s7Cq{tt+Wt)K9>l+SzC|r zcLH!BhK^kepW`w-WsYI5om9bu2iIT&P04!4%P^MAOXOzP*KjS;|5n0`03%6;lcXA_ zL7z2`qh!_~gi+46mHjbk?5|8^>3rHZ^Z%#hPf9tqQi89ILmC`#*VnVNa|u@RYxl66*vBt zpvBZO#wua4cqUn}seuzmj*0WOFrLOs#7DX5Cr4yaC*4ED9RIgKoboYLi)Typ&q>{y zu!X!WZCvh{(5BE;wAT6Fi;FaRbw=rw_Nm=XK}=4sqbQ8$EienkA-MuUdLYRaezEAPWv+v5W>~@8sk9eP&3Qw!cJe4j|LwKJPn9b>Sur!;n6aVJ?gIQ zZCya_{zj*gl7lrw2-1+S=g8B0n<4y%IZ)u z6f;o;^OMzOtNB~Vc5->gBq(=cJ71!Y-UVEdb)NT`->Xs0YMB8A&eTtmN04p`6-^C= zBxA%-e^4xe?Hf>C}t4nT2VPiq${+o`Jsk3NU z)E1Rw$TX6v$IY16VN5%{uZVl@vJmPkB^Sn>hIW_0n1;>N$6mr|l&6e|r`kTg~N-hS^B}fVT0Q(}@tb~;Y=^csY>iXlKRygJ2x2X9Ws;ohu z@)o|J$|Kt)uVlb-Xe?_^i)ag*hoW#E4>h`pd2O�|x-gHa$IbyvGKSEgJtrf{vp> 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

;w|$ja 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

R;2v*H!yTle2 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

e9Yy+$?WBotD+=cy;Bf$CS|h@$$g-WwRw$pCp>R z1woFSJ>2N-rXaHTaNiul(O!Fq37Q%9_C3;{kRGCcWDH|BKGRXBntCs)s$?KORJ z|5w?zmtK8n3;?_Bvo=SaY#N+2f&L(T9vdicYY-}7CVl|h)SQWLeCW$sk^s!4G-iH} zH934<)B6R?ta_L z$dX@>FsEu%;u;8&Ef~J{n-`IkjZl({7OBuq4JD!YR%jkoqbJbkPhJ1|U2IeUs(dZs z7x3X!votZ(9oY0MG%qLRPIL~#uox&Vp^GI@J7P*_VDC&JF->u_r+M(p&u;*&PF>u5 zBy%Mn5Jc3-)0#E~f}5nwFmBE@)lb+ir|~(m?!bsbUSPCEV8uP%qqP3+?^@tg)~2$N zN-TgTVN+Kld{gVgG#FXILS*3FGYU=Wc$+#0nMRxIt?J@m$1{@V`|5Z_Jz0R&?v0$0 zRhqNPP8H+t&h{>+B~VcS17hlT`R$fXopIt-eK16MIZO$l+XrA)m$`vg&$jM~TZ>FC z+)fypXo)hdMfxwYj;ux2$(BYh{AzzMy(rS4Cz+6`)@!!O4`03s4kX>pN*b@HogHx6 zD8(gH*6zum-0E9r+)}uq-AcIW3P-Sui~S}IX;!!=&K_N_iFTL3b7DmXpJwPjr|#%UE8_Par#1BS1|y+OaMGyz=wDXQ+5Z zL{PdAj)tJ(Ki(SP%bkc~s;OxAI|H_NJpp_>VtKy~Xr!McV@+ZWBbu?fyTnTTHbHYa z@wXgw%cm}%z6=H8N6joVn>x~TjP-MsTe6t|`fkJiJw?++UWBc#k7APgJ#mP`Ab*Pr z9{GFS+SVtzaCMUqQM%XLbvqfD1*t`MPFyA#P|2JH z=?RF19FFcTcCmJch-dgYdJ;`>TThX@o{_eNG%2lgks4a$cjP2~UNk8*XY(m>W^bcLRiYxou5 zf(3Z}nq^!M$&hYc>x?88(xYf@3%7f-s_6t}4LGa8b2e-OLm&W}Y`VqzwDJkxA)fF_ zr#s&(qHEYixWe;R(m9+12(#!d}!rTrv#Y=U4$%xH)hb|eg)z2f9FAeF+^vJuT zV-6JBb!Tn*<7w*l7l@`UYGm5sj64QBCClA9ho!q0ze*Plps~IeN0%Y8lFA5d&=AkC z%?*-z(jA_gvJ*b1PTvX(&vLUoLQUQPe#8()AcYr1*0YOk$A&s!W0`wJs%n`pg^;Ys zLaYfuZAu_rL6=i@xk723R8$TbrlXV|Qc z2}6%5$kQgb(gvE!!kms!y1SUNL59{kA!C#@r73KUb~j&!t07;QE2V34v4JM{%T{@y zv&^;2IxDSh{rLL%Eh|@t*U&eFMK}5#w^;kHF$4R!2`x{uy&uv?*XVNBNXucN8F!&) z!a(}x0QkmTaQp|Q@1#2jeQ)y#z9r+h&aL^ht_w2!3n^cqLckw)fBqMmTm7?D-gH-) z*nPH2jL#s)PaEDZMz+>;*6xn>R&*Ah{?~N>7v=vuWry0PBZ>;@hc!w%t5t48V)fcr z=mr_70C@p3FhY3=Ya#Poe$;bTjk$$M8wu71l|THbe*}dWz7N}bIpPdsX3bvT>>RU4 zGx4%V?`Q0@cX34TXYaUOn$%0Uu(eOlNKbEV@I3wTIdYxmX@9xtZrA&^68-eYOeiv~ z1)pf@#r`u|f_YL@0^elifr8H~Hkk;b^;Z|Al}++wmMQ6^bTEzLY7{jSdTN>x)nS^3 zKCK+n9V`=intO8EQL6h^2)b9xK&}e`1=*rEZ^wv%j(9B4KoWUaMF60bR}l?uP6$Yz zroefwp^i9-1sXFN2KO5u*-1-4D8Z!NDcX_p0$`%4Bk{4}DSiW#62doZyKJGlN*T3( zE`xu!6%UKRNk$+8F~rNrgq`e9WC+dIAfpsO5oQ^0KS)$_W&w3^O;&P+z6*Jy75Hc( z5?A4{wjA{4`ZSUEZ+S{a1bke3NoRumn0U1h?FMv)F?anD6Tvx2JbJ(MA^t@}CP3YsyP{JzG zAqOq&a^rpXa?7IiY$20bN#rTRR`iCV$AXL~Fp}>JBlIE3idZia)-vy2lAN3@LUVTN z1~)r3gGlYn@_9c*Ib2r<$|RI{oYR_3r6-I@oVAtv85vR_%!QSUliY&Q779h21!L>- zIw4&!oS}qX4jIuP7}z+zQ?}INMg{^wV+{donaS7jFzzN%hZ#25s;~;HbfvMhg4)uS zK8@zqR{DS|PHXvDOK}*YFbBb`B1-H$rT)2b&v~S3j67*z_^j}0a8c=)VS@@Y9dxN; zmXtfkvG(awraote&=Lvk!?dp;@ z%Wb0vn1T2EhCG@c<&Yt;Ijwbcf{R;rM+cA0K0IxnJI@Lgls|j}&SdJAIhZgZtq4I| z)~clBYB`7VdX*b9f0&2|$}e<0ZX#w+M=MGY{a4JiwLmx_s7&li!Td9 zg&U0G1Wx=|$&86K9zXphTxL-!Bq+XSQg2vrr)1*O{2Wp)b*p{C)M@NkY*a69ylgC^ z*V~G(iQAf8>-no1U^EQR;^x~Gw3~~t1LO3x@%0G;&ax(~BD<;wZ6WVlhIs?wl_(Rg zCI&v|tVr$(xv$ObWo~VXNt4BwPR<@+@=VAcQqL0F70p5_!`G7H2iSbND|7v4I9NXa zl_K}I8-ghAH8U<3L_-Q2e7ri~(wZYS9+Mdz30g($itPCuiYG?9OxS}#3_M~kM^iik zcpDFg+l73S5rqPE-Zdn2jE`i%yr^m-*m*w(zzN)r7X1+c9&s2-j*5N zC|Izxii9r`Nr?e|c1eZW9cBzC>5sqV=z1H1ttln#96PfkU(Uf$)Km|8pSxX0eknUwN69dTFN11zLGl ziI)VTGHr{D@}=q`&4ltX?xso-i>z`NN$3^%^ONvFNSQKbtvttm*_b97B_GnjH0mGp zyj#nEj%4Nvpr*3Kq3{w#;8VQw6ETUeToIHJG*(bfSt+ahmngKG;+aqQV7pA2qFC{p zKm@l)bx#GKeM42$Yy8uH89V&bxTy5(Y6(75Eet;c>i-w>_F}#A0Bv=C##KJJaG(3|RI`!9*{7FO++c5(^o%^MyOr-kJ<}%B$iQRi8nl zK=qm*{d0NlKnl{G6Q%Kep}go24^=zY3Q6W4wVJ-Zt!1To<{fk*hU&)8Y>87mbjYH+ zv>)zk&4qyh{86iJHd%Xis5N?ZP#1lt9;g}7Ke9R`u3S>P84S87U@E!u1qc@O#qw=< z!JJX(GDfPB+0``&%FX@~Si%^;XULufSS5y~Wtiv*z2W}nfJfu=q~X6DeY5+N)%^av zO@Br`|L+jtf1I?E{C^nrt7$o*ECV);rrnIqf2glO8qkwM5x|UoUQLuqSqV_XYjFeI z68R;DZ}p9hC62*d(n-yAWyCW~6B4_&3$A7ql|op7-ZNE)?Uv4!f1Mxdx8L4=MU%ZD~vpEew?I83v>ry@UYvzxcU?9l(74{eIO$BGUGFpaduI_?HyTgJKO?(_+u zPqo=i1$om-x7R{3<-OHJPanGtM1jOxuQl9xPy38$xoPL8-D^*ib1cD zFxe?b^?2MNcbvb_u_-jX1cK>2uD|Lg?vkv!X_y>=_5m7Qr@blH>9EyjZbCpkm%Az$ z&aS-ua+`Z1lKy2UFP&jFCoiSmxy+;(Ac`twH=8pf?l`$R53~6%7Eedh_|AL{DkGE1 z8}+RTEv1E%eZR1m@5#&JE`a!Ak+lY%ILY5{0Or?r1S)yr6Z?qb5M&C=0(uq`5JI|< zgk*=%NlO~Hl?h6nOQ6MHWujsNdQ>^N2ieI`x`chBo2}l>b|NjRCeiwn`Y?McZ0tfK zo7xomgs>2IftYS&5nz_2#*G(I)+rS<%uC=v@|60jSKrvf>fgcA!ko%W29ME;gs?Ed zB~-u6LeGnbYNJFa$|Si=Y4z3jAg8V9IaQhT(y%Rc-VAXWdFvPMbFm2uOWsV9lWaBu|`1OH2nxZ-LH`ch@3Nud%8f8Oe?RZ`mW6|5V)wj+P zRZFfH6=~G+r5fkZx=z+2N&B}I7aTPb{2PEx0885< z)}=HiPOdcEy6NXib#>X*!Xy9B?C7gHUx1Y!wWjkmasOtm6CrlX|;PRsn3G2jM0^y^^PpCQp&LQRD2qVWZC!g8tg*&p?md zV6v_5i5k&i;DR&pgs92lE2xGeWlYYhj4>2p{4()-mff+7`1NR5$%K!v^tt zX!u;F@s(~I^E1bKu&2|XxgJp9=&lDi+cnh$R*S!0!XV_K@eOMg)-#-s3ju z(G=_-*+-ukK5})|Z3BUe7)V)PgXTq0w14AAfH!2-z8v(Qh>JKD8*X}531)zm`i41a z3;ff{vQ6b}e3|v(PN~(acHFMDGgMWN5GkydyCa)cvOmk;OXzVCW|PB;Io9&g=A9z{ zqz-di>m!=HN#)nGCdAr{g5)UMjGqdP%2#=$XVSgWbv^54SLFU1%kKo`a?iRJV=^YB zMukIEl@Iw>t}8N3RbFkV3ZAtMnQBfiaFzOZeXg|kvU-izv{ID6q>obhHq)E-Al%b# zqNYM&MU|88A5RBVn!Q*+GLGG8rzG3!e>~5MiJv|S`+GBn8~{cae>)$r_mGPjrrEC` zvb#Nd+4|>{Ol;V*8uKKu0T!M>YEzDEJrEx&HD&i+jaP^8g#Q=Z3SMQ}oODM3#nR2U zD;x5aa8aMqx@G~NOXpwf=fzXrtWMG1+7Gv*CNMO15Mv~=ST$Kj2{hUvZv;^*s{DMA zR;%#m1!xFVKZC+ec%x(-&E!}9VgVw-JImBEM3mIwJe;egOf+ZK&z;9BD2^Z8;L=WX z`-`UyM3(fu=nQZpx4hJ|^i z!8>ED!$U?9Gh@(eo$QiVX@$W(r(B37C*Wu=hw-+yqkrzBWR`Y3=&g*W4Yhyx2~4G% z?buZ^@qm!D65P7cG>qN#*hMFC?AcFfzhI^FFHIWy#|#`OCEmW`jU znSOvi09*f)PQJAJg4HCky0WyUxqmHyD)P1u)A0MrbBR6jRW z)8n02A}i1XzX4&kbf27Qm7`$47hz}DEg-xx6vy#2X*2!&3p@p}q(nGemQkdrB}0tfij}uZoA*@!n*& z-avR<`7ud7Yluqrm`%;W4-NZK7lr}KtKCMx7rfkrm_1hRp#dJ*J30DYImIgu3to{r zJ{iPcxl+^de~+xcz}MJ#o7D!WxaVOatR_|U%8jMMa!E@@5>9Q>sLO`ZwBLx0$BKMD zP+j-2P{py~u9*%c4X~%*XPkgG`unuF3FG7Z4{Q8cE*7WWAp!=af1%w~Epl%gM)D)B zgBFq5)8$Z}L!%FK=7YFGW#jO$3$At{&?X|zE$Qs9oG-g3Sg)a-bxC-1_hHW9u;Y9* zQ|97RSu7gX7^GGM#~DICAKdhjbHa98_;tFTV0Iy^a%crY?1M$N2fhD}UEYa%jut+} zDe9l%6sCWNU2LuYSyvJI9}wn00F3IJ(m!H8n;%wq5yH%7Rw`bJg5XM}swBPu;fSvm z`8(yO$Y|=)tPHF2wT(25awl&WPDS0XmRaWZB}}+KFYo1!f6j&Qn7V4P8W@~AG1fm_ zwjTLBacy%vS^2yjrRae*?A!c^5|>~{@kb~nXxgKm4t`-k9^%M68is&EUv;1mhOfRp zuM4CiTp${xQ|p(f#}dUdvQqknab)jLlYm_GwFOP|8>7|4tq=miaB@fBnSqt4fS`gu zVJ;9+(v(?+?e*a%lfSKN?85{x3njn$X={$cQb9y*Tjy`5E`)y#^K+uj7@0z?Hbqu4%0C&nA?E4y z^mJUM&e}e!$#E=hWN73s4t|!G88u^r0=d?UL^nSjI_bz@Ys$)bFtJJ$jY<)mwnmlA z-L|kQP?B5ibPg~qxDr<$uJV7Cfe|;dm?i&h0&YR3j4t8FYRgGOMUko<PpTkfUCHi$jfIgifd-?GRgg&Awc9YlU&86dgklzd$li2XH74y#1$II;26oJ1)vK?o;F1^X+u8e+!#XfFRt>1DlW zYj!eBCuX7g@6`ONFQF&0^AS>1)&@_BLlB1JCHIL9ktzXTEctcB29>S`57^Wq(LC|G zpPE+!xoBCW-QNx{5pHYW8t#4)xR8~qh!cWDkj^LK-HEl)$jmUoG(sxp- z54oJj+M`sDy5TmHuQG1+WH4^^Rqz)m@?qNUH%02=#NEJe6|QLs7+_xQdPCulJR`b> zHbruXzW>07dDg@R{a>0sSOY2>rs8f!KN;z_?I$TDM>4T0$JejR*6!7>HIg@e2oUREe5|zn-3EH<*C<$MqN&b|f}}mYn*3X4yTEo3j8j9^7QGcQK+$ph7Mf()D+~>RnNNbp z^J`$l9Yw~fjg*0exgw=Qa;~1b(`IWiGA~oF?^42ZS67J^wT!Pqub&M0^Uc6{~~tXA;>>4{gJ}>GyKC$=#!1e6dhk4+SS0W z{Nb2PV8P2R=E$eUFR)Q(b2s2YXue9X9)2;}5&S8FMN*6Hv7h0B<%E#uJKO(@pgFExNBep)!4l zHl@!=a#DW%E6}ffMKr;;hZvmek2K+-ZPZKH5Vs)l6W#~X_QRLmH&SM$HQ7}%ddX2j zVLJ?ldwCihLig9u0S2c%l7vfLPA4*VdY0~1qd2z|p^gZ_{Q{AZIX@u8iaA+tol{)l zI_%67IuSBF3kO4&*^t{x^bIA)Eg_OpUz7U?F}$_ZC`*wC8TtOVlKvbC2Ad1}P!SwM zBrSzs4>J{G&X+EKzi1ZHahe4+W_gBc#=A@sWb?(eK?sAZ?=(_hlaK0rd=spEI6JKM z37k+!ZqM!Cwzw+a=7(YU_{s`BLChK>bH1Yak;tLU$#db-_VoOw6H}8Gz0%-I!%Gb+ z%Sr^7Rp^o>4o7X;fz=7ESH?IZFSuiF_myf9&;F2V2^wz+pprd&REqUZlt43^LNc2| zBllfD9=1m&4>w14?wP__?re07bHhCcBGC~bvIq64azX$13da9TiTqbrNK%h*MODN6ka1y4up$Kl`F|WBr3T4v9^n$7xOEn(r8&j>Q%IAtJ0sZgOfYO($AuS*3VIIoM2O~`0 z3o$VGX9oPIu!DCJvjNkA{d&U}j+^HWH}0H00R}u&Pd)h?5dgxALa@-Dy*gqyu&Mi8 zjHinTPfz8B1)%q2#0n4C#WwU(pTS3}7gP4C{}B^z)Lm#e5EI0nv$yWE5PrkuL*3_R z*ypXL?;|&e1lWGs|NfjCp6`>mua4xS9EksRgMo+cl`rVGPbpi%Ub+VbabQjiSTxd# zQszt#wLQ_U=3gzzVNMJ!mf^9nSv11zS9_{X*_N}TSIc1ivkmqipM z=gTska&p)SK%O*ZX}_QSTcL5Nn(_)X@r+LMp9YI(ua~rA5T`Waxh*0<&C)?9Ys$i_ zb>p%+=N)!e_MccU$ zjRet)bHX2Q%=sOI!hm3oIALg$n2gM;!9iNFrFMu>>=e?{S!PGhH95hYdY|t?BAup( zKknfRkv)a;}ku8>mzy_D7cYlCZrSUDBD7v zsMHR#BQ$h8NVz*+WRBu;8LhGzNv`^~ww78{Ty_41mY&PMg_;k}$VE)pe7_Nr*&7mqfas?Tkb15|piwbE_x?jpoqyOsKGn^9#*dSRb4E5rXOsi3+*^hq>4d+^;;ri!rx)=}R1;)cNpt*F?&ar~Zl&++tVrNwYo)_P$2R}LNh zy^DQ+Hr;Zr57g>j=vkgR#mx@er*P4$HIaxsb5iZK9nc9>C~pM`6p=ULGA6Q~zF6_K zVCj}v0NJrIY2%BbN1IN};2s1+f$5x;SQOYYRqNlc=nre9uLJLYsls3}<8=0$Uh_|6 zUmmG0W7GV+rhllp5uf8lFUO2lvn6l3)@hE!&w$?Qub$vg_e;vG-cvIJ zQ@tAwo_5DH?}%yb3NFWhe)(?J8{8_hxMi_zPd;2Qz{xwfOgZC^Ox@d<*{IQBCiWw? z{$Yimo8heI4cHv~l#hbPu|A?xo$2k%gx|*g6yKfMZ4+pXs~W3im?_x%xI@l8yvvim zm@9utlW=7DsIm0YYL-#6Dr$KonR&?rww?M7R480p`&h5)W}jspgpMzaK;jVRSqp+5 zsZ0^xN)PFPTV5X_()BM7TtbJG6QuE-2V4Hlo-;5AwqCOdsU=2YOaN5xmq2yDoe@N~ zPR6YXv%8EvJ>1*!MbKy&W1JIyUPfwm^L)aD|0^WV6J;6$&Z8#%^vBu^m4rAI?@;vQ zhnHoCp(VJ80fWbj*1jdTmdr9B_p4*A@6qB8<$`?$e=J3jz@SqRWs6Os5z4%Kqtgr} zN0rHG_$;xtxe;T)Yw0t6(e7t~4aFvQ;EVenic9iJa9SH7F7XR-SP>YSOeCrKN+4ct zAukz-9oCjeWl8#n{W8V*`A33QuUMg|$cI1>bf=Wac02c4IZ>Y7BnkT?#Yb>)Rz4e$ zytV2)#2_S;gZ3=Xg5z>{wJR+pD5kN#9nuh>Sj3A4V3wT1DYOY9ONSE^58B zrTJPu-_#8Lt0o+S28(uDQ;D=PY<-DaDm}(13na5Iq3mHkm1#GxzQSr6)x5S2ge`kq zLo)}bNH7ZO&*KtrkMVSk_d$2P5+%7b(7pnER1rR3iNqkk|DJgH*q{hdJGoHg9l1+XeTQ=XKTdrbq4^oxN}S+_hVTYg!d$ z&1um;L1-P57#~?IPY8K`nKC4z66;=vzO;|J$>KJ3Qrw#0L2n-*L7YchMdvZWSL^3) zG8Q-VucBYYgSEYV{CA9KF4dwb@Trs7fdBG^^4|~%!vE+A4IDu-ASZ)=-v5OZEB|BH zC0Lpf2(N-DZxfzk@q>KLLaSGi8BwHPq;F8GvER7oGfE^gEp)}RF(u?LShmHL_fD^i zbFTHWMfN)W;-dEyY=12HnFA(Tg7?&_>6PuzH^!Hv?d=cnYv?ZV90>HiRAE{_3hDac z$UqG!bd=CtMH<@rD=MoG%7iLOw|2DUy_K*tt!wy1aN`LQv(h@yF9|HqiTYvxK&4o=cu;B!aMap}$qDhwv5TBepim7HvkqkX>}bWOo! z$>L)xYJ+6$8x$s0Qa9)bs^UK=sES*^a(*D>__lS}_I1z6hiUXQK}=>fB#Yi^cXe7GZ5vKrPks%V*CxXCXb%qcGlom&Q?=q z)X}r2%yB1X86RZvz#31ID}uy;;qdNN-iVi>bnOT96(F)QDZDa7Sq>v~Vvn#VqufFkOyM3iIj8 zvcs+5Ad8Hb3<9acpf==h%|MR@?zN>`D~^R*ntcvH(5#lran^%7S30UN-TmA5CEY1Z zSD^Blaq!GdvYBdR`c`BP-OE9eq*rMS5l7MKBldv#1L_zzdTs{|d&TF`@p}U@s7*|| zR+R8cRPY~(u`QR8sejvKT}fFe=Np~pJ3!g98!V;*ZJhlI(d*dLJTYOJDs?I}`Snd^ zm7I9+^@yN`JQ+cOU??d;g&~?1MjUzS3ppyQF+mQ?VyU*cWh;|9;jk=LOqQ&w#S<2^ z1mlgN_((4GqBjsnfdRACx)o5^Q7i_BgK(erQPNFq$kR=4==-z$kl3^O5ZQ5pJ;D>n zYb-f?*Aa|Hplhr@ks-K#fn=JIfubK|k%T4VM+WJZ6@7U6EmqRq!OO+?`1M}h#>3Fi z%fZ4;yk}~1_+W`~$$c{N`qgm1h(dz{U)?Bz5)`rpyBJ*#Uk&tp8(6_%z55EUVxCwP zPQ%yl)Vb8yLBrZZ1$e_G@Ti}0^LmvE8S@S2$gv+NP&H+w3J5T6Id@?Zxn0azOW(7= zMqzxi>inR_6Wk{_58!V0{539SF_f)LGg>8M3OL(i+O1`XS;2itp%O;iu_7q3N#bVI40=Wbil=x2k2vtAyr z%9bMuA0xynZt}zs{*g9><80A{<3X5-=?_>DQ7kSF-URwddDf&v(wpNyCa}Jn5WHjA zJknRLq&>q};6bn&dC?7CjBd5sUJ;}~08hFjn29zdlP?)iYcCfliKu`gf-aD)StfGC zJpds#kK;e`I{_E;+-JNV9C^e*{6f9)U)3SJNIVlM&t~@s1GGHB3-ayZZcmiR_l@B+ zaL%QAH*>ZtlsiyO?}Ha&qe6+)u6E1{9#b<@)He=ssjb3)X(3@H2WHFJhZvr~Q#~o^ z>$CQOorfYBan~LYf7!%&{dlu)@Um~Prj$~zED5_T%dR(L61t+^N(#C7xfJBL(PbKi z+dbhML-Wub1AJAi^rlU|X?#ID3HG}nm-oZmnD;d$4z0qqRrLO$jkS~1SI{gTZf70~ zjJsssN0mkSX<%gz`?3-~fV0~xCMO}G*) zPZeJQHVP*MqmR%K1GC%U>#sqFUso!-8UvV_54O6wfPN%f%PTYFY<;m-KRO}(eXtew zhhq*OykYlvi@lX_td$ZAVd zh7IwmYwtPI;$~7f+l!ImFJ$)O0EW>s*kAH}wof#muPo?tl*zFTqTQaFYQEBg z|1zOZ66(l~&re1RUcyHCTLda45Ca7fV5ia3;tK_q@YV2Zm3Rx~E~gNordJu41!|NMqTe+r5tk3rC81YFWOP$sD6~ zNCv#nx@vN7cL`QoDVG%NuhA9A05)?K=HRMK8w-bg)umGsUDgrgQ4LBqRyQ5=*W%jz zW4i~2%F$1iWw8FN#lmOFgZVj;^+pGixpwfDStOlNW&njgs8SgoNCCwrsNBDb*mn$X z03U{UXrEx9UN8V>b2$JiUy(1z)M27L@z^X2v6BkiM6(m?@%I%0bA_OWY6$@s@;}9J zJ;OkEj{F$c%%6wNtuVKEDCo7;s>ke`Y(yPvPnRsr;^`ehPR3NE2_yT{;Qh1a?Xh(h z(Q-<5sL7$2Vfia=WF!%p)T)0+7WMDMj*hG(OvYlCHseLAwo$kzuQ|U9E>0~03WocJ zH66>J<<2}hic1GZxFRHCnBOYlMRXHjG7{(B$BEIKKqM(te@%${$1G?k>753aaEwkr z%8>C2J@X?jkTt-6tfbGxGl*&fbAX*KS?Yo@Lv%ZQHJzW!tu^X4$rF+qP}nwq|{`zFz69-Fv_3 zq?0GPf4~^yxp&bVIbr%DL3$>R)3z=LD=jAkUOc)VJripB@t}VXGd{(|Mdx^(iBlI{N!T(@V|a>{J%Yce?I`# z4@ayel)u%~mL$eo#Qn1L_Pxjm6EUk0#K;B*q;*#CtI4%SCrk0ws+OJsot7@DsgDA> zk0KOBiTCNUB|S|GcW{1Z=0bamRsm(;;Dg(4iPH&v%YklfZ9j12Bq;9JpTL+@6HSBv6$V#8-QXeReF6} zlS!smC{(p8Vefg9dNPXd>kXpbThBFa!^6QxQ?1$juEl*}kPolB&VI6pGzRGWG>>D+xNIsg2y#IGR3e~U_D#di{T zK)az^>vrYxvp+`J-of9$OB!Lb#8ic$xxLr-mDsG1ri=r3fB>_zatG9zw->_c6Nq>5 z3gJUJ`=Xo@e`sMcbX2ZQp_$G6M(W;hI!gZtX5(8$E-o=LbL)uH(+mBSf!Hg^dF5W8 z>5Mv)&G8T!t-GHXtb67L)w6uZ>Qiul^Qkh@@tPI=a_b2|{|WUr^xMYg-Q-L|zx{jd zuV25Qj|FE(D?QJwuQ{(&%*_EDCojK1Zi~-Rx=_KM5DuQc!0s3jGlbvVcZ{@^D41OW z@5JLu4E{h%Mv%6>P1>@ zz~hg>_PWr!`z_B@zDnsQ4(uBx*5uyU@OAo&hQ*4>F)i=4YJ+i>^^VQM*?uujs^up@ z9I1b!U~Dq@JXj}f99HFN`bCoUNGW*Xi{p%CUZ-WCQBQBdXPGzPeUj0V;hZS&7xvL? zA6qUAOpF)o9mNnh+k`a&uiTyL=dW(rvYuv`7=o%vGq=nNK?$HyyBGW;a?{{fjA8Lp zy+ooms&@=R*YjmV3mb9uWy_1aBT=f7vaP(z$=`DOVK8vk1%?s7#R9S-#;5DnqdEK0 zhwXwdOfPs3Cy^3eyt&KZvkJU$<$}8ZVh0-uzlU$9eV`ev@P;IZ+Y&K!MiKWk+mkP` zJi2;a;jvTSf<%96uH6)d$ZGf~<((ZmhB2w4=T!(hM=7*x#1uvDu-!KHbN?RUp7&Ru z<`y~=ylP~^9M-&*vwNf_9SH3SV|NAg4)lE#Jdw9Oxg9;*Hfs!KBdLu7b76|hr>zx? zV&U%PGlskW>8(|+l@eVHu!ZT8pXHCYB+@FJ%g-B2Dx6~vAlGw$&<>LqGYCl-crq9X zx#CQYgqE~_`%f#)WEEGw!(5)i+H1*sMPPRo?r~uH{N)ecX>HlV#!zMYG#>5jH)S8b z#KZf_fCR%4!Vtf8jLs=}b?0Pe&f6z*hZqJK6>Z^cG00K_7ZKI|9PJC;ChGH!$>XsQYJ`-$jsz3uNknMidEWJd(l5P{U!H2G@i* zdZD;e#Tn_}CIaHPSqo%3eS*c#zPLljec_$4>{GN;Yu4K`M!V|fGFU1FD*SMyy(gub^ld+WF?QYvjL7VAxRvOpK z->;b;t&Y{896~qD1Oz8N$wB5A4XFN9efuDhY!Sbp>3%&0Bm1PNDR9YJwM3E0@K)45 zN-f)A>=-sR-vm=Okxh%?iO&5b@Z~*aP`9X|3+nA%INSS68U))2H!=Q&KgE{IxqsZK ztI&ho^sAj%@N&{dDef8xf>-W-%@xjSfu-D2gdHDa&S}i$NOa`Z3&9q8~WLBt)yC z=VHyr9mz<4B%(P)2kj}d>!f9JB(-i!We-h81^R)E=|~DqEUQbS$3VEUd7gHvL9UaF60Hd6W?1|M<2i*VN#Zt)nY1 zE-E9@XyNHKR-M(sbn?u}SHVnqSO=ysD64)btZnqSNDS+WC7dbJn7J_Qi*92j8XETn zunf2o?i_i0L4wqiiH&M-=$57?sd5@lj0j{jNCi~!1c-NU69x|TC}5?aGU^(CNqSq% zgd1=06jfQlf^&k4|EiBu_TQW?hddO(fF&!yZ<`A7H{$*(MIK%U@#PRN1X!#d1HL|d2r)F#*nVkX zjJ@U{86xkHDI)I(4geNjvPOB)J0~8krTaSRL#ND=o5snYi<)SNq6T-uEl79bElPLs zld~uOy_j?YoQPqu@5%HRVs~E)V)wuc;`Cl;Ae5Uzzf>#v9@r=O9wO~R*F)+Hz|jRk z%byvys1`BL=kBqJ8k2Ryy87kmWwdDf26crLj&ioD#Ca*yn|K!#sMF0wAWY&qsZ+^~;SSshpEGUbjZ z{Tc^yf(=3>{y%1$_yO4HqW|5zN#L?zBu{*|b zNw^J}_SSH@rKmb_OTTE21s*-wU&Y}*ym3ogKt~GJ@M7}B1_Lx2Bb-O4+#;r2044-^ zYl*TGTa-qdXGvXF3bl5N@qjz@0pj3&ssm(b06(znYJ!R^2ZLmm>#QO2y2ZuJu{D9; z>92|)c?^W`obyJ`7f6G=S4+STf<%71*2cG=n4^~8#n(spcNuNL2%nNSKF6v}>qB^Y zWfm)&@_Z7Z;2~g(rO%4;l<~-RcJ*=UGx171C=M>(xsPnAlYMB~yFR*Ba=OCJnQd^Z zyi6Lxz&xm7S(nsY_zoexSf7fH&r1Rt8%$gsp-DJG5Ynmw;>S;}Y7*W;PRZiQEN2$4 zwI+NZAeee3&dg_C>$ey#D!+pI2FZabwf3gC(f5n;`6Gn#)BVv4B>Mty@B@Ezu#*}u zj3XL}^FG&lrvo!XI=blFn#%_3dO7O|C0`#cj+)<6p#UM#{-1Jr|AGYkWb!f;ej*M3PfhkuY9TVtR!-*PwvJB!bC^** zQ(aU+?(y^Mg*OJPQYllxU`42K1~Au8HuwE-a-~Tn!~@pEex$?NG1t%aayh!dxnmwrH?3OVnk#dt~9mO+Q(29UaPakdY;w zj@NM!m3CwS4BI(47LEfJzv5V=>DRlzK{mr6xBReEKmjTpzZQxNd~aHLqPc>$_yM4N8c?06=@O+-U@K zSK{?@OIYRq_Y5=&0Xt{~RxTQ~{&Cs+R2#)=2?H>LV&ErQ+`(fVsrJ!Yc z=(RUIx?;V*cSWlbOpMPEB?l4_V#d)eO`p081XQ|ipER$2R1YSZQ01L|8Haz>& zv=_2!NuiGL;EI~V4z7Je?z@c6SB;SB7Ew_Q-DHzfa}e@wsPOs6nZqx6O*VuO}fait2xTDcqA zR*P*ZMO(*1D=hPZQ?8M3(esx##wV&mmvEqN`9J;K;HO!4~SpchIAdV83 zLDKUopmyn?5f4+xt8psn*7EZ;s@+@=;sdqYty=8 zk+nnDRSfVp?#MMn%-M7PnMxm9Y)Tu2cmfN6xMYcXIfYAMj2n}*(Q#KjfHx? z%4-eG0%8-J_25Q`Pl1f9^(m#13=zLnUuP%|0>Bh1POl-i)QMGkmPmRQK)TgQCzjda zKDrzlU}8=mrfT47hgu|;M}x=&4; zS-)(T*ml%wex}}$eWHHhG+y}ijp#%3d`Xj0;pPd`vBIOWu0>_vu_#X+rQ~M-QH8Q* z!u9nZO~Zfjf(JF5gx^2BVCRpd6~#Z4LjQAIQrxgv;D_f?6qKf;=$a4Kl#<#Y7FWY3 zhA*R35Gu-T1R;?`;O3ZST_3F*@K7ABx$6bHRR|4(3A6kN3VHIF$!0Qjad}?3!Q%tq z9zg>70ELB41c!=7Y(|ZWd6Fw}?zbq@x>-|g#_)2U0 z@O1K#a8nN#uD)`f3RaoFQ0W=WeQ=RuZ^wkfk*rYktO|}M?R>xCkBcWlX&2P2M$WEw zPvO;n*pUdx!f(xAg4J^GiV@FX!;7<^cd^HYBpjw{9*C1iHRj4-pOx^;m1P+EF zim^;n9RN+6$fNfaRs(KnpLetl5MuPP7JTW^j7ur7Dy{%aB}PES_t=)?dq z1DjE^@T#z$yH;5b;@d`&AHn7F#j4M-&0=UKSvwC*MK~!I*brKWXqx#|gj};lvGOA6 z5?KBOMw{0UIC7KmHK#Ur(TMZ#wPAQ6lFlbvya$&=BwIL1h*fY8!%vDi`>xOOd{P)*?EvN?~XIBt^SV;Vzf|~6gZ_$r@!cQHoCL>L(Xl`xy zV~L^freyouSpRMnvoxn#4P=Uba( zkT$}Q5?BwOR=1sW*Ro(_DH>-RgPOTD#PQC4Dt_U7MC(7Rfr3T;!hVopc=&mQK7R(K zK!js=#mxO2Zz4yqMr3wJew;Gam`=P-I!-d{eD7~=I$?8>P9o;QQ^EA5+w|S=4Z|&q z-wZ{Es8@dWFlhU_#7o8Rd5Q?9ULr$&w(CaANAC*8q8>h-l!iu>C(GD}m0!wU1F>En z4#;>)`%1Xoe!<<3l(gNMDsdO?w}yu(bLa0XpyWL5I=V$-aaZp{uyyYaqmhgzyqQBR z1%x~mco656m=F?~ux6*PWyg>eM_RQ2yK;3CC=IhZ;U!rbb|3FlEagZNA0_A`-DQSrvr2x)4K4ZQ`^C zuU>ykBuq~WAIFD@%jQHprWIyRW{Aqh5)YZf$d@K&Gdp1Lm_%M->>_I)i1<^nNsBh( z)wyPQArL6zA^)kzWq4Zc67m=}SwqTLYVeq3e)YVb6?W45Q=o^W(7yBd=rp~%NF13M z*mRes#5tk6!G^^~V`YSqam3F~_XvtHomzMc9;B^CX>W$N<)nz}T7ITgLbqsPj3y_R zc|pPEz`$cD454FV%E^^2Encb?bOVH4oyjyNr_OzHxL%XNxkvDYKT;h&8CXSyjM9Nz zAfoOeI{#)hxr%Y(^s1UXEs85I1f0R_^v6!who8#aY#@ZW(Xb%!INMs-=SzVw3DVqB zYGhc3=1G(?Ih*jKipH>jYs1!hZMkAkf?EXNWAn8>xMmkP>w<+l$~1Jj3I;QK=%?XV zm-7hI=+R~u+w+te%w<;+xSzcnsORF(&h8egp>PJ#+~Sy!P-t#THq}mILG#o1!OR|k z;x0hja+4Uq&78G^EOGzSF(%>Ie|fwCy`wed!8owd^(M}1O<|LMQKDVE73B_N%0AuT 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%0AZz6}`@}C(k{P*>q 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%0A$oqtWZ(TPN1 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%0ASlEEB^J_* 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 literal 0 HcmV?d00001 diff --git a/spring-mybatis/src/main/webapp/WEB-INF/web.xml b/spring-mybatis/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..569b5ef9b1 --- /dev/null +++ b/spring-mybatis/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + + myBatisSpringServlet + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + /WEB-INF/conf/mybatis-spring.xml + + + + + myBatisSpringServlet + *.html + + + MyBatis-Spring Integration + \ No newline at end of file diff --git a/spring-mybatis/src/main/webapp/index.jsp b/spring-mybatis/src/main/webapp/index.jsp new file mode 100644 index 0000000000..b60222e7de --- /dev/null +++ b/spring-mybatis/src/main/webapp/index.jsp @@ -0,0 +1,34 @@ + + + + + + + +

+ Login     Signup +
+ +
+
+
+

Welcome to Online Student Enrollment Application

+

Login to explore the complete features!

+
+
+ +
+
+ + + \ No newline at end of file From 44f5742f16c7020de4487670f33a1e6527137308 Mon Sep 17 00:00:00 2001 From: azrairshad Date: Fri, 24 Mar 2017 09:55:02 -0700 Subject: [PATCH 173/291] (BAEL-746) How to Copy an Array in Java (#1474) --- .../com/baeldung/arraycopy/model/Address.java | 61 +++++++ .../baeldung/arraycopy/model/Employee.java | 25 +++ .../baeldung/arraycopy/ArrayCopyUtilTest.java | 163 ++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/arraycopy/model/Address.java create mode 100644 core-java/src/main/java/com/baeldung/arraycopy/model/Employee.java create mode 100644 core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java diff --git a/core-java/src/main/java/com/baeldung/arraycopy/model/Address.java b/core-java/src/main/java/com/baeldung/arraycopy/model/Address.java new file mode 100644 index 0000000000..43c6d77fe6 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/arraycopy/model/Address.java @@ -0,0 +1,61 @@ +package com.baeldung.arraycopy.model; + +public class Address implements Cloneable { + private String country; + private String state; + private String city; + private String street; + private String zipcode; + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getZipcode() { + return zipcode; + } + + public void setZipcode(String zipcode) { + this.zipcode = zipcode; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + super.clone(); + Address address = new Address(); + address.setCity(this.city); + address.setCountry(this.country); + address.setState(this.state); + address.setStreet(this.street); + address.setZipcode(this.zipcode); + return address; + } +} diff --git a/core-java/src/main/java/com/baeldung/arraycopy/model/Employee.java b/core-java/src/main/java/com/baeldung/arraycopy/model/Employee.java new file mode 100644 index 0000000000..757a8f8ec1 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/arraycopy/model/Employee.java @@ -0,0 +1,25 @@ +package com.baeldung.arraycopy.model; + +import java.io.Serializable; + +public class Employee implements Serializable { + private static final long serialVersionUID = -2454619097207585825L; + private int id; + private String name; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java new file mode 100644 index 0000000000..2c9a97c496 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java @@ -0,0 +1,163 @@ +package com.baeldung.arraycopy; + +import com.baeldung.arraycopy.model.Address; +import com.baeldung.arraycopy.model.Employee; +import org.apache.commons.lang3.SerializationUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Arrays; + +public class ArrayCopyUtilTest { + private static Employee[] employees; + private static final int MAX = 2; + + @BeforeClass + public static void setup(){ + employees = new Employee[MAX]; + Employee employee; + for(int i = 0; i < MAX; i++) { + employee = new Employee(); + employee.setName("Emp"+i); + employee.setId(i); + employees[i] = employee; + } + } + + @Test + public void givenArrayOfPrimitiveType_whenCopiedViaSystemsArrayCopy_thenSuccessful(){ + int[] array = {23, 43, 55}; + int[] copiedArray = new int[3]; + + System.arraycopy(array, 0, copiedArray, 0, 3); + + Assert.assertTrue(array.length == copiedArray.length); + Assert.assertTrue(copiedArray[0] == array[0]); + Assert.assertTrue(copiedArray[1] == array[1]); + Assert.assertTrue(copiedArray[2] == array[2]); + } + + @Test + public void givenArrayOfPrimitiveType_whenCopiedSubSequenceViaSystemsArrayCopy_thenSuccessful(){ + int[] array = {23, 43, 55, 12, 65, 88, 92}; + int[] copiedArray = new int[3]; + + System.arraycopy(array, 2, copiedArray, 0, 3); + + Assert.assertTrue(3 == copiedArray.length); + Assert.assertTrue(copiedArray[0] == array[2]); + Assert.assertTrue(copiedArray[1] == array[3]); + Assert.assertTrue(copiedArray[2] == array[4]); + } + + @Test + public void givenArrayOfPrimitiveType_whenCopiedSubSequenceViaArraysCopyOfRange_thenSuccessful(){ + int[] array = {23, 43, 55, 12, 65, 88, 92}; + + int[] copiedArray = Arrays.copyOfRange(array, 1, 4); + + Assert.assertTrue(3 == copiedArray.length); + Assert.assertTrue(copiedArray[0] == array[1]); + Assert.assertTrue(copiedArray[1] == array[2]); + Assert.assertTrue(copiedArray[2] == array[3]); + } + + @Test + public void givenArrayOfPrimitiveType_whenCopiedViaArraysCopyOf_thenValueChangeIsSuccessful(){ + int[] array = {23, 43, 55, 12}; + int newLength = array.length; + + int[] copiedArray = Arrays.copyOf(array, newLength); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == array.length); + Assert.assertTrue(copiedArray[0] == array[0]); + Assert.assertTrue(copiedArray[1] == array[1]); + Assert.assertTrue(copiedArray[2] == array[2]); + Assert.assertTrue(copiedArray[3] == array[3]); + array[0] = 9; + Assert.assertTrue(copiedArray[0] != array[0]); + copiedArray[1] = 12; + Assert.assertTrue(copiedArray[1] != array[1]); + } + + @Test + public void givenArrayOfNonPrimitiveType_whenCopiedViaArraysCopyOf_thenDoShallowCopy(){ + Employee[] copiedArray = Arrays.copyOf(employees, employees.length); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == employees.length); + employees[0].setName(employees[0].getName()+"_Changed"); + //change in employees' element caused change in the copied array + Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); + } + + @Test + public void givenArrayOfPrimitiveType_whenCopiedViaArrayClone_thenValueChangeIsSuccessful(){ + int[] array = {23, 43, 55, 12}; + + int[] copiedArray = array.clone(); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == array.length); + Assert.assertTrue(copiedArray[0] == array[0]); + Assert.assertTrue(copiedArray[1] == array[1]); + Assert.assertTrue(copiedArray[2] == array[2]); + Assert.assertTrue(copiedArray[3] == array[3]); + array[0] = 9; + Assert.assertTrue(copiedArray[0] != array[0]); + copiedArray[1] = 12; + Assert.assertTrue(copiedArray[1] != array[1]); + } + + @Test + public void givenArraysOfNonPrimitiveType_whenCopiedViaArrayClone_thenDoShallowCopy(){ + Employee[] copiedArray = employees.clone(); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == employees.length); + employees[0].setName(employees[0].getName()+"_Changed"); + //change in employees' element changed the copied array + Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); + } + + @Test + public void givenArraysOfCloneableNonPrimitiveType_whenCopiedViaArrayClone_thenDoShallowCopy(){ + Address[] addresses = createAddressArray(); + + Address[] copiedArray = addresses.clone(); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == addresses.length); + addresses[0].setCity(addresses[0].getCity()+"_Changed"); + Assert.assertTrue(copiedArray[0].getCity().equals(addresses[0].getCity())); + } + + @Test + public void givenArraysOfSerializableNonPrimitiveType_whenCopiedViaSerializationUtils_thenDoDeepCopy(){ + Employee[] copiedArray = SerializationUtils.clone(employees); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == employees.length); + employees[0].setName(employees[0].getName()+"_Changed"); + //change in employees' element didn't change in the copied array + Assert.assertFalse(copiedArray[0].getName().equals(employees[0].getName())); + } + + private Address[] createAddressArray(){ + Address[] addresses = new Address[1]; + addresses[0] = createAddress(); + return addresses; + } + + private Address createAddress() { + Address address = new Address(); + address.setCountry("USA"); + address.setState("CA"); + address.setCity("San Francisco"); + address.setStreet("Street 1"); + address.setZipcode("59999"); + return address; + } +} From 11cdf67fad28587f3be0c1c4ca498ff541de81e2 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 24 Mar 2017 20:06:32 +0100 Subject: [PATCH 174/291] Merge modules (#1471) * Merge modules * Update pom.xml --- pom.xml | 1 - spring-security-basic-auth/.gitignore | 13 - spring-security-basic-auth/README.md | 13 - spring-security-basic-auth/pom.xml | 267 ------------------ .../persistence/service/FooService.java | 23 -- .../java/org/baeldung/spring/MvcConfig.java | 39 --- .../baeldung/spring/PersistenceConfig.java | 14 - .../baeldung/spring/SecSecurityConfig.java | 15 - .../java/org/baeldung/spring/WebConfig.java | 17 -- .../web/controller/FooController.java | 74 ----- .../org/baeldung/web/controller/LinkUtil.java | 30 -- .../web/controller/ResourceCreated.java | 35 --- ...esourceCreatedDiscoverabilityListener.java | 35 --- .../controller/SingleResourceRetrieved.java | 29 -- ...ourceRetrievedDiscoverabilityListener.java | 32 --- .../web/controller/TestController.java | 28 -- .../main/java/org/baeldung/web/dto/Foo.java | 11 - .../src/main/resources/logback.xml | 20 -- .../src/main/resources/webSecurityConfig.xml | 23 -- .../src/main/webapp/WEB-INF/mvc-servlet.xml | 5 - .../src/main/webapp/WEB-INF/view/homepage.jsp | 7 - .../src/main/webapp/WEB-INF/web.xml | 43 --- .../src/test/resources/.gitignore | 13 - .../MyBasicAuthenticationEntryPoint.java | 2 +- spring-security-rest-basic-auth/README.md | 3 +- .../MyBasicAuthenticationEntryPoint.java | 15 +- 26 files changed, 10 insertions(+), 797 deletions(-) delete mode 100644 spring-security-basic-auth/.gitignore delete mode 100644 spring-security-basic-auth/README.md delete mode 100644 spring-security-basic-auth/pom.xml delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/persistence/service/FooService.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/spring/MvcConfig.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/spring/PersistenceConfig.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/spring/SecSecurityConfig.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/FooController.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/LinkUtil.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreated.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreatedDiscoverabilityListener.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrieved.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrievedDiscoverabilityListener.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/controller/TestController.java delete mode 100644 spring-security-basic-auth/src/main/java/org/baeldung/web/dto/Foo.java delete mode 100644 spring-security-basic-auth/src/main/resources/logback.xml delete mode 100644 spring-security-basic-auth/src/main/resources/webSecurityConfig.xml delete mode 100644 spring-security-basic-auth/src/main/webapp/WEB-INF/mvc-servlet.xml delete mode 100644 spring-security-basic-auth/src/main/webapp/WEB-INF/view/homepage.jsp delete mode 100644 spring-security-basic-auth/src/main/webapp/WEB-INF/web.xml delete mode 100644 spring-security-basic-auth/src/test/resources/.gitignore rename {spring-security-basic-auth/src/main/java/org/baeldung/security => spring-security-mvc-digest-auth/src/main/java/org/baeldung}/basic/MyBasicAuthenticationEntryPoint.java (96%) rename {spring-security-mvc-digest-auth/src/main/java/org/baeldung/security => spring-security-rest-basic-auth/src/main/java/org/baeldung}/basic/MyBasicAuthenticationEntryPoint.java (96%) diff --git a/pom.xml b/pom.xml index 7c1cacbd33..929f98a674 100644 --- a/pom.xml +++ b/pom.xml @@ -161,7 +161,6 @@ spring-rest-angular spring-rest-docs spring-rest - spring-security-basic-auth spring-security-cache-control spring-security-client/spring-security-jsp-authentication spring-security-client/spring-security-jsp-authorize diff --git a/spring-security-basic-auth/.gitignore b/spring-security-basic-auth/.gitignore deleted file mode 100644 index 83c05e60c8..0000000000 --- a/spring-security-basic-auth/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.class - -#folders# -/target -/neoDb* -/data -/src/main/webapp/WEB-INF/classes -*/META-INF/* - -# Packaged files # -*.jar -*.war -*.ear \ No newline at end of file diff --git a/spring-security-basic-auth/README.md b/spring-security-basic-auth/README.md deleted file mode 100644 index ebb404063f..0000000000 --- a/spring-security-basic-auth/README.md +++ /dev/null @@ -1,13 +0,0 @@ -========= - -## Spring Security with Basic Authentication Example Project - -###The Course -The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - -### Relevant Article: -- [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) - - -### Notes -- the project includes both views as well as a REST layer diff --git a/spring-security-basic-auth/pom.xml b/spring-security-basic-auth/pom.xml deleted file mode 100644 index 4cb0efb9e2..0000000000 --- a/spring-security-basic-auth/pom.xml +++ /dev/null @@ -1,267 +0,0 @@ - - 4.0.0 - com.baeldung - spring-security-mvc-basic-auth - 0.1-SNAPSHOT - - spring-security-mvc-basic-auth - war - - - - - - - org.springframework.security - spring-security-web - ${org.springframework.security.version} - - - org.springframework.security - spring-security-config - ${org.springframework.security.version} - - - - - - org.springframework - spring-core - ${org.springframework.version} - - - commons-logging - commons-logging - - - - - org.springframework - spring-context - ${org.springframework.version} - - - org.springframework - spring-jdbc - ${org.springframework.version} - - - org.springframework - spring-beans - ${org.springframework.version} - - - org.springframework - spring-aop - ${org.springframework.version} - - - org.springframework - spring-tx - ${org.springframework.version} - - - org.springframework - spring-expression - ${org.springframework.version} - - - - org.springframework - spring-web - ${org.springframework.version} - - - org.springframework - spring-webmvc - ${org.springframework.version} - - - - - - javax.servlet - javax.servlet-api - ${javax.servlet.version} - provided - - - - javax.servlet - jstl - ${jstl.version} - runtime - - - - - - com.google.guava - guava - ${guava.version} - - - - - - org.slf4j - slf4j-api - ${org.slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - org.slf4j - jcl-over-slf4j - ${org.slf4j.version} - - - - org.slf4j - log4j-over-slf4j - ${org.slf4j.version} - - - - - - junit - junit - ${junit.version} - test - - - - org.hamcrest - hamcrest-core - ${org.hamcrest.version} - test - - - org.hamcrest - hamcrest-library - ${org.hamcrest.version} - test - - - - org.mockito - mockito-core - ${mockito.version} - test - - - - - - spring-security-mvc-basic-auth - - - src/main/resources - true - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - - - - org.apache.maven.plugins - maven-war-plugin - ${maven-war-plugin.version} - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - - - - - - - - - - org.codehaus.cargo - cargo-maven2-plugin - ${cargo-maven2-plugin.version} - - true - - jetty8x - embedded - - - - - - - 8082 - - - - - - - - - - - - 4.3.4.RELEASE - 4.2.0.RELEASE - - - 5.2.5.Final - 5.1.40 - - - 1.7.21 - 1.1.7 - - - 5.3.3.Final - 1.2 - 3.1.0 - - - 19.0 - 3.5 - - - 1.3 - 4.12 - 1.10.19 - - 4.4.5 - 4.5.2 - - 2.9.0 - - - 3.6.0 - 2.6 - 2.19.1 - 2.7 - 1.6.1 - - - - \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/persistence/service/FooService.java b/spring-security-basic-auth/src/main/java/org/baeldung/persistence/service/FooService.java deleted file mode 100644 index 02db7a733a..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/persistence/service/FooService.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.baeldung.persistence.service; - -import org.baeldung.web.dto.Foo; -import org.springframework.stereotype.Service; - -@Service -public class FooService { - - public FooService() { - super(); - } - - // API - - public Foo getById(final Long id) { - return null; - } - - public Long create(final Foo resource) { - return null; - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/spring/MvcConfig.java b/spring-security-basic-auth/src/main/java/org/baeldung/spring/MvcConfig.java deleted file mode 100644 index 74c11478ee..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/spring/MvcConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import org.springframework.web.servlet.view.InternalResourceViewResolver; -import org.springframework.web.servlet.view.JstlView; - -@Configuration -@EnableWebMvc -public class MvcConfig extends WebMvcConfigurerAdapter { - - public MvcConfig() { - super(); - } - - // API - - @Override - public void addViewControllers(final ViewControllerRegistry registry) { - super.addViewControllers(registry); - - registry.addViewController("/homepage.html"); - } - - @Bean - public ViewResolver viewResolver() { - final InternalResourceViewResolver bean = new InternalResourceViewResolver(); - - bean.setViewClass(JstlView.class); - bean.setPrefix("/WEB-INF/view/"); - bean.setSuffix(".jsp"); - - return bean; - } -} \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/spring/PersistenceConfig.java b/spring-security-basic-auth/src/main/java/org/baeldung/spring/PersistenceConfig.java deleted file mode 100644 index 4ea0053f48..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/spring/PersistenceConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan("org.baeldung.persistence") -public class PersistenceConfig { - - public PersistenceConfig() { - super(); - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/spring/SecSecurityConfig.java b/spring-security-basic-auth/src/main/java/org/baeldung/spring/SecSecurityConfig.java deleted file mode 100644 index f40c599834..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/spring/SecSecurityConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan("org.baeldung.security") -// @ImportResource({ "classpath:webSecurityConfig.xml" }) -public class SecSecurityConfig { - - public SecSecurityConfig() { - super(); - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java b/spring-security-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java deleted file mode 100644 index fa6f5f6d56..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/spring/WebConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -@Configuration -@ComponentScan("org.baeldung.web") -public class WebConfig extends WebMvcConfigurerAdapter { - - public WebConfig() { - super(); - } - - // API - -} \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/FooController.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/FooController.java deleted file mode 100644 index daa797ee36..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/FooController.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.baeldung.web.controller; - -import java.net.URI; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.baeldung.persistence.service.FooService; -import org.baeldung.web.dto.Foo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriTemplate; - -import com.google.common.base.Preconditions; - -@Controller -@RequestMapping(value = "/foo") -public class FooController { - - @Autowired - private ApplicationEventPublisher eventPublisher; - - @Autowired - private FooService service; - - public FooController() { - super(); - } - - // API - - @RequestMapping(value = "/{id}", method = RequestMethod.GET) - @ResponseBody - public Foo findOne(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) { - return new Foo(); - } - - @RequestMapping(value = "admin/foo/{id}", method = RequestMethod.GET) - @ResponseBody - public Foo get(@PathVariable("id") final Long id, final HttpServletRequest request, final HttpServletResponse response) { - final Foo resourceById = Preconditions.checkNotNull(service.getById(id)); - - eventPublisher.publishEvent(new SingleResourceRetrieved(this, request, response)); - return resourceById; - } - - @RequestMapping(value = "admin/foo", method = RequestMethod.POST) - @ResponseStatus(HttpStatus.CREATED) - public void create(@RequestBody final Foo resource, final HttpServletRequest request, final HttpServletResponse response) { - Preconditions.checkNotNull(resource); - final Long idOfCreatedResource = service.create(resource); - - eventPublisher.publishEvent(new ResourceCreated(this, request, response, idOfCreatedResource)); - } - - @RequestMapping(value = "admin", method = RequestMethod.GET) - @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) { - final String rootUri = request.getRequestURL().toString(); - - final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo"); - final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection"); - response.addHeader("Link", linkToFoo); - } -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/LinkUtil.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/LinkUtil.java deleted file mode 100644 index a41ebb5a5c..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/LinkUtil.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.baeldung.web.controller; - -import javax.servlet.http.HttpServletResponse; - -/** - * Provides some constants and utility methods to build a Link Header to be stored in the {@link HttpServletResponse} object - */ -public final class LinkUtil { - - private LinkUtil() { - throw new AssertionError(); - } - - // - - /** - * Creates a Link Header to be stored in the {@link HttpServletResponse} to provide Discoverability features to the user - * - * @param uri - * the base uri - * @param rel - * the relative path - * - * @return the complete url - */ - public static String createLinkHeader(final String uri, final String rel) { - return "<" + uri + ">; rel=\"" + rel + "\""; - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreated.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreated.java deleted file mode 100644 index a677888101..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreated.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.baeldung.web.controller; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.context.ApplicationEvent; - -public class ResourceCreated extends ApplicationEvent { - private final HttpServletResponse response; - private final HttpServletRequest request; - private final long idOfNewResource; - - public ResourceCreated(final Object source, final HttpServletRequest request, final HttpServletResponse response, final long idOfNewResource) { - super(source); - - this.request = request; - this.response = response; - this.idOfNewResource = idOfNewResource; - } - - // API - - public HttpServletResponse getResponse() { - return response; - } - - public HttpServletRequest getRequest() { - return request; - } - - public long getIdOfNewResource() { - return idOfNewResource; - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreatedDiscoverabilityListener.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreatedDiscoverabilityListener.java deleted file mode 100644 index 8d19ef82fc..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/ResourceCreatedDiscoverabilityListener.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.baeldung.web.controller; - -import java.net.URI; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; -import org.springframework.web.util.UriTemplate; - -import com.google.common.base.Preconditions; -import com.google.common.net.HttpHeaders; - -@Component -class ResourceCreatedDiscoverabilityListener implements ApplicationListener { - - @Override - public void onApplicationEvent(final ResourceCreated resourceCreatedEvent) { - Preconditions.checkNotNull(resourceCreatedEvent); - - final HttpServletRequest request = resourceCreatedEvent.getRequest(); - final HttpServletResponse response = resourceCreatedEvent.getResponse(); - final long idOfNewResource = resourceCreatedEvent.getIdOfNewResource(); - - addLinkHeaderOnResourceCreation(request, response, idOfNewResource); - } - - void addLinkHeaderOnResourceCreation(final HttpServletRequest request, final HttpServletResponse response, final long idOfNewResource) { - final String requestUrl = request.getRequestURL().toString(); - final URI uri = new UriTemplate("{requestUrl}/{idOfNewResource}").expand(requestUrl, idOfNewResource); - response.setHeader(HttpHeaders.LOCATION, uri.toASCIIString()); - } - -} \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrieved.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrieved.java deleted file mode 100644 index 3de7918105..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrieved.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.baeldung.web.controller; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.context.ApplicationEvent; - -public class SingleResourceRetrieved extends ApplicationEvent { - private final HttpServletResponse response; - private final HttpServletRequest request; - - public SingleResourceRetrieved(final Object source, final HttpServletRequest request, final HttpServletResponse response) { - super(source); - - this.request = request; - this.response = response; - } - - // API - - public HttpServletResponse getResponse() { - return response; - } - - public HttpServletRequest getRequest() { - return request; - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrievedDiscoverabilityListener.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrievedDiscoverabilityListener.java deleted file mode 100644 index 45cd7c4d13..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/SingleResourceRetrievedDiscoverabilityListener.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.baeldung.web.controller; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; - -import com.google.common.base.Preconditions; - -@Component -class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener { - - @Override - public void onApplicationEvent(final SingleResourceRetrieved resourceRetrievedEvent) { - Preconditions.checkNotNull(resourceRetrievedEvent); - - final HttpServletRequest request = resourceRetrievedEvent.getRequest(); - final HttpServletResponse response = resourceRetrievedEvent.getResponse(); - addLinkHeaderOnSingleResourceRetrieval(request, response); - } - - void addLinkHeaderOnSingleResourceRetrieval(final HttpServletRequest request, final HttpServletResponse response) { - final StringBuffer requestURL = request.getRequestURL(); - final int positionOfLastSlash = requestURL.lastIndexOf("/"); - final String uriForResourceCreation = requestURL.substring(0, positionOfLastSlash); - - final String linkHeaderValue = LinkUtil.createLinkHeader(uriForResourceCreation, "collection"); - response.addHeader("Link", linkHeaderValue); - } - -} \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/TestController.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/TestController.java deleted file mode 100644 index f68cfb2eb7..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/controller/TestController.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.baeldung.web.controller; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -public class TestController { - - public TestController() { - super(); - } - - // API - - @RequestMapping("/permitAll") - @ResponseBody - public String permitAll() { - return "Permit All"; - } - - @RequestMapping("/securityNone") - @ResponseBody - public String securityNone() { - return "Security None"; - } - -} diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/web/dto/Foo.java b/spring-security-basic-auth/src/main/java/org/baeldung/web/dto/Foo.java deleted file mode 100644 index 352045989d..0000000000 --- a/spring-security-basic-auth/src/main/java/org/baeldung/web/dto/Foo.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.baeldung.web.dto; - -import java.io.Serializable; - -public class Foo implements Serializable { - - public Foo() { - super(); - } - -} diff --git a/spring-security-basic-auth/src/main/resources/logback.xml b/spring-security-basic-auth/src/main/resources/logback.xml deleted file mode 100644 index 1146dade63..0000000000 --- a/spring-security-basic-auth/src/main/resources/logback.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - web - %date [%thread] %-5level %logger{36} - %message%n - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml b/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml deleted file mode 100644 index b0d483768b..0000000000 --- a/spring-security-basic-auth/src/main/resources/webSecurityConfig.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/webapp/WEB-INF/mvc-servlet.xml b/spring-security-basic-auth/src/main/webapp/WEB-INF/mvc-servlet.xml deleted file mode 100644 index eb7ce7b5f8..0000000000 --- a/spring-security-basic-auth/src/main/webapp/WEB-INF/mvc-servlet.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/webapp/WEB-INF/view/homepage.jsp b/spring-security-basic-auth/src/main/webapp/WEB-INF/view/homepage.jsp deleted file mode 100644 index 7cc14b5dcd..0000000000 --- a/spring-security-basic-auth/src/main/webapp/WEB-INF/view/homepage.jsp +++ /dev/null @@ -1,7 +0,0 @@ - - - - -

This is the body of the sample view

- - \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/webapp/WEB-INF/web.xml b/spring-security-basic-auth/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 77a830c6d5..0000000000 --- a/spring-security-basic-auth/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - Spring Security Basic Auth Application - - - contextClass - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - contextConfigLocation - org.baeldung.spring - - - - org.springframework.web.context.ContextLoaderListener - - - - mvc - org.springframework.web.servlet.DispatcherServlet - 1 - - - mvc - / - - - - springSecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - - - springSecurityFilterChain - /* - - - - index.html - - - \ No newline at end of file diff --git a/spring-security-basic-auth/src/test/resources/.gitignore b/spring-security-basic-auth/src/test/resources/.gitignore deleted file mode 100644 index 83c05e60c8..0000000000 --- a/spring-security-basic-auth/src/test/resources/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.class - -#folders# -/target -/neoDb* -/data -/src/main/webapp/WEB-INF/classes -*/META-INF/* - -# Packaged files # -*.jar -*.war -*.ear \ No newline at end of file diff --git a/spring-security-basic-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java b/spring-security-mvc-digest-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java similarity index 96% rename from spring-security-basic-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java rename to spring-security-mvc-digest-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java index 968237227f..c51c0a0bc8 100644 --- a/spring-security-basic-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java +++ b/spring-security-mvc-digest-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java @@ -1,4 +1,4 @@ -package org.baeldung.security.basic; +package org.baeldung.basic; import java.io.IOException; import java.io.PrintWriter; diff --git a/spring-security-rest-basic-auth/README.md b/spring-security-rest-basic-auth/README.md index 328f46ed46..43ab08b8ca 100644 --- a/spring-security-rest-basic-auth/README.md +++ b/spring-security-rest-basic-auth/README.md @@ -9,4 +9,5 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [RestTemplate with Basic Authentication in Spring](http://www.baeldung.com/2012/04/16/how-to-use-resttemplate-with-basic-authentication-in-spring-3-1) - [HttpClient Timeout](http://www.baeldung.com/httpclient-timeout) - [HttpClient with SSL](http://www.baeldung.com/httpclient-ssl) -- [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) \ No newline at end of file +- [Writing a Custom Filter in Spring Security](http://www.baeldung.com/spring-security-custom-filter) +- [Spring Security Basic Authentication](http://www.baeldung.com/spring-security-basic-authentication) \ No newline at end of file diff --git a/spring-security-mvc-digest-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java b/spring-security-rest-basic-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java similarity index 96% rename from spring-security-mvc-digest-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java rename to spring-security-rest-basic-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java index 968237227f..6e580e7a22 100644 --- a/spring-security-mvc-digest-auth/src/main/java/org/baeldung/security/basic/MyBasicAuthenticationEntryPoint.java +++ b/spring-security-rest-basic-auth/src/main/java/org/baeldung/basic/MyBasicAuthenticationEntryPoint.java @@ -1,16 +1,15 @@ -package org.baeldung.security.basic; - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +package org.baeldung.basic; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.stereotype.Component; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + @Component public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { From 092d883dde466c9cbbf210db6569df8b5e5a8bd0 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 24 Mar 2017 20:12:13 +0100 Subject: [PATCH 175/291] Revert "Spring State Machine" (#1485) * Revert "Merge modules (#1471)" This reverts commit 11cdf67fad28587f3be0c1c4ca498ff541de81e2. * Revert "(BAEL-746) How to Copy an Array in Java (#1474)" This reverts commit 44f5742f16c7020de4487670f33a1e6527137308. * Revert "Bs santosh spring mybatis (#1479)" This reverts commit 3140ea166d05c59b605eb3ac0b5d55a116344c6e. * Revert "Spring State Machine (#1424)" This reverts commit 319dd2653a073f310db05b6121696ebfa7049968. --- pom.xml | 5 +- spring-state-machine/bpmn/forkjoin.bpmn | 116 ------------------ spring-state-machine/bpmn/img/forkjoin.png | Bin 50788 -> 0 bytes spring-state-machine/bpmn/img/simple.png | Bin 22706 -> 0 bytes spring-state-machine/bpmn/simple.bpmn | 76 ------------ spring-state-machine/pom.xml | 31 ----- .../ApplicationReviewEvents.java | 5 - .../ApplicationReviewStates.java | 5 - .../ForkJoinStateMachineConfiguration.java | 74 ----------- ...HierarchicalStateMachineConfiguration.java | 47 ------- .../JunctionStateMachineConfiguration.java | 60 --------- .../SimpleEnumStateMachineConfiguration.java | 53 -------- .../SimpleStateMachineConfiguration.java | 105 ---------------- .../config/StateMachineListener.java | 16 --- .../ForkJoinStateMachineTest.java | 45 ------- .../HierarchicalStateMachineTest.java | 37 ------ .../JunctionStateMachineTest.java | 24 ---- .../statemachine/StateEnumMachineTest.java | 33 ----- .../statemachine/StateMachineBuilderTest.java | 35 ------ .../spring/statemachine/StateMachineTest.java | 47 ------- 20 files changed, 1 insertion(+), 813 deletions(-) delete mode 100644 spring-state-machine/bpmn/forkjoin.bpmn delete mode 100644 spring-state-machine/bpmn/img/forkjoin.png delete mode 100644 spring-state-machine/bpmn/img/simple.png delete mode 100644 spring-state-machine/bpmn/simple.bpmn delete mode 100644 spring-state-machine/pom.xml delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java delete mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java delete mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java diff --git a/pom.xml b/pom.xml index 929f98a674..791430ba0e 100644 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,6 @@ spring-sleuth spring-social-login spring-spel - spring-state-machine spring-thymeleaf spring-userservice spring-zuul @@ -210,9 +209,7 @@ rabbitmq vertx - - - + diff --git a/spring-state-machine/bpmn/forkjoin.bpmn b/spring-state-machine/bpmn/forkjoin.bpmn deleted file mode 100644 index 0cb060f74b..0000000000 --- a/spring-state-machine/bpmn/forkjoin.bpmn +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spring-state-machine/bpmn/img/forkjoin.png b/spring-state-machine/bpmn/img/forkjoin.png deleted file mode 100644 index 642ab6949d18b49012529d7c5b9b14f909c9d701..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50788 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�gf@SIUg-QO`umQ3S)QlWiV3@kS`RLu_ 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 D__yV@ diff --git a/spring-state-machine/bpmn/img/simple.png b/spring-state-machine/bpmn/img/simple.png deleted file mode 100644 index 7a79bf1d895a401b2b59d4b093e770f3546bc3d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22706 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 AC;$Ke diff --git a/spring-state-machine/bpmn/simple.bpmn b/spring-state-machine/bpmn/simple.bpmn deleted file mode 100644 index 8ed463e9f9..0000000000 --- a/spring-state-machine/bpmn/simple.bpmn +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spring-state-machine/pom.xml b/spring-state-machine/pom.xml deleted file mode 100644 index 5393626083..0000000000 --- a/spring-state-machine/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - parent-modules - com.baeldung - 1.0.0-SNAPSHOT - - 4.0.0 - - baeldung-spring-state-machine - - 1.8 - 1.8 - - - - - org.springframework.statemachine - spring-statemachine-core - 1.2.3.RELEASE - - - junit - junit - 4.11 - test - - - \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java deleted file mode 100644 index 971fc5dde7..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.spring.stateMachine.applicationReview; - -public enum ApplicationReviewEvents { - APPROVE, REJECT -} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java deleted file mode 100644 index 1df2db1f86..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.spring.stateMachine.applicationReview; - -public enum ApplicationReviewStates { - PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED -} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java deleted file mode 100644 index c55104a627..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.config.EnableStateMachine; -import org.springframework.statemachine.config.StateMachineConfigurerAdapter; -import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; -import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; -import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; -import org.springframework.statemachine.guard.Guard; - -@Configuration -@EnableStateMachine -public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAdapter { - - @Override - public void configure(StateMachineConfigurationConfigurer config) - throws Exception { - config - .withConfiguration() - .autoStartup(true) - .listener(new StateMachineListener()); - } - - @Override - public void configure(StateMachineStateConfigurer states) throws Exception { - states - .withStates() - .initial("SI") - .fork("SFork") - .join("SJoin") - .end("SF") - .and() - .withStates() - .parent("SFork") - .initial("Sub1-1") - .end("Sub1-2") - .and() - .withStates() - .parent("SFork") - .initial("Sub2-1") - .end("Sub2-2"); - } - - @Override - public void configure(StateMachineTransitionConfigurer transitions) throws Exception { - transitions.withExternal() - .source("SI").target("SFork").event("E1") - .and().withExternal() - .source("Sub1-1").target("Sub1-2").event("sub1") - .and().withExternal() - .source("Sub2-1").target("Sub2-2").event("sub2") - .and() - .withFork() - .source("SFork") - .target("Sub1-1") - .target("Sub2-1") - .and() - .withJoin() - .source("Sub1-2") - .source("Sub2-2") - .target("SJoin"); - } - - @Bean - public Guard mediumGuard() { - return (ctx) -> false; - } - - @Bean - public Guard highGuard() { - return (ctx) -> false; - } -} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java deleted file mode 100644 index 708dbd3077..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.config.EnableStateMachine; -import org.springframework.statemachine.config.StateMachineConfigurerAdapter; -import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; -import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; -import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; - -@Configuration -@EnableStateMachine -public class HierarchicalStateMachineConfiguration extends StateMachineConfigurerAdapter { - - @Override - public void configure(StateMachineConfigurationConfigurer config) - throws Exception { - config - .withConfiguration() - .autoStartup(true) - .listener(new StateMachineListener()); - } - - @Override - public void configure(StateMachineStateConfigurer states) throws Exception { - states - .withStates() - .initial("SI") - .state("SI") - .end("SF") - .and() - .withStates() - .parent("SI") - .initial("SUB1") - .state("SUB2") - .end("SUBEND"); - } - - @Override - public void configure(StateMachineTransitionConfigurer transitions) throws Exception { - transitions.withExternal() - .source("SI").target("SF").event("end") - .and().withExternal() - .source("SUB1").target("SUB2").event("se1") - .and().withExternal() - .source("SUB2").target("SUBEND").event("s-end"); - } -} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java deleted file mode 100644 index e1bae10fb7..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.config.EnableStateMachine; -import org.springframework.statemachine.config.StateMachineConfigurerAdapter; -import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; -import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; -import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; -import org.springframework.statemachine.guard.Guard; - -@Configuration -@EnableStateMachine -public class JunctionStateMachineConfiguration extends StateMachineConfigurerAdapter { - - @Override - public void configure(StateMachineConfigurationConfigurer config) - throws Exception { - config - .withConfiguration() - .autoStartup(true) - .listener(new StateMachineListener()); - } - - @Override - public void configure(StateMachineStateConfigurer states) throws Exception { - states - .withStates() - .initial("SI") - .junction("SJ") - .state("high") - .state("medium") - .state("low") - .end("SF"); - } - - @Override - public void configure(StateMachineTransitionConfigurer transitions) throws Exception { - transitions.withExternal() - .source("SI").target("SJ").event("E1") - .and() - .withJunction() - .source("SJ") - .first("high", highGuard()) - .then("medium", mediumGuard()) - .last("low") - .and().withExternal() - .source("low").target("SF").event("end"); - } - - @Bean - public Guard mediumGuard() { - return (ctx) -> false; - } - - @Bean - public Guard highGuard() { - return (ctx) -> false; - } -} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java deleted file mode 100644 index 4e11851644..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.action.Action; -import org.springframework.statemachine.config.EnableStateMachine; -import org.springframework.statemachine.config.StateMachineConfigurerAdapter; -import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; -import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; -import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; -import org.springframework.statemachine.guard.Guard; - -import java.util.Arrays; -import java.util.HashSet; - -@Configuration -@EnableStateMachine -public class SimpleEnumStateMachineConfiguration extends StateMachineConfigurerAdapter { - - @Override - public void configure(StateMachineConfigurationConfigurer config) - throws Exception { - config - .withConfiguration() - .autoStartup(true) - .listener(new StateMachineListener()); - } - - @Override - public void configure(StateMachineStateConfigurer states) throws Exception { - states - .withStates() - .initial(ApplicationReviewStates.PEER_REVIEW) - .state(ApplicationReviewStates.PRINCIPAL_REVIEW) - .end(ApplicationReviewStates.APPROVED) - .end(ApplicationReviewStates.REJECTED); - - } - - @Override - public void configure(StateMachineTransitionConfigurer transitions) throws Exception { - transitions.withExternal() - .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.PRINCIPAL_REVIEW).event(ApplicationReviewEvents.APPROVE) - .and().withExternal() - .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.APPROVED).event(ApplicationReviewEvents.APPROVE) - .and().withExternal() - .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT) - .and().withExternal() - .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT); - } -} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java deleted file mode 100644 index fe4e0f82ce..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.action.Action; -import org.springframework.statemachine.config.EnableStateMachine; -import org.springframework.statemachine.config.StateMachineConfigurerAdapter; -import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; -import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; -import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; -import org.springframework.statemachine.guard.Guard; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.logging.Logger; - -@Configuration -@EnableStateMachine -public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter { - - public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); - - @Override - public void configure(StateMachineConfigurationConfigurer config) - throws Exception { - config - .withConfiguration() - .autoStartup(true) - .listener(new StateMachineListener()); - } - - @Override - public void configure(StateMachineStateConfigurer states) throws Exception { - states - .withStates() - .initial("SI") - .end("SF") - .states(new HashSet<>(Arrays.asList("S1", "S2"))) - .state("S4", executeAction(), errorAction()) - .stateEntry("S3", entryAction()) - .stateDo("S3", executeAction()) - .stateExit("S3", exitAction()); - - } - - @Override - public void configure(StateMachineTransitionConfigurer transitions) throws Exception { - transitions.withExternal() - .source("SI").target("S1").event("E1").action(initAction()) - .and().withExternal() - .source("S1").target("S2").event("E2") - .and().withExternal() - .source("SI").target("S3").event("E3") - .and().withExternal() - .source("S3").target("S4").event("E4").guard(simpleGuard()) - .and().withExternal() - .source("S2").target("SF").event("end"); - } - - @Bean - public Guard simpleGuard() { - return (ctx) -> { - int approvalCount = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); - return approvalCount > 0; - }; - } - - @Bean - public Action entryAction() { - return (ctx) -> { - LOGGER.info("Entry " + ctx.getTarget().getId()); - }; - } - - @Bean - public Action executeAction() { - return (ctx) -> { - LOGGER.info("Do " + ctx.getTarget().getId()); - int approvals = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); - approvals++; - ctx.getExtendedState().getVariables().put("approvalCount", approvals); - }; - } - - @Bean - public Action exitAction() { - return (ctx) -> { - LOGGER.info("Exit " + ctx.getSource().getId() + " -> " + ctx.getTarget().getId()); - }; - } - - @Bean - public Action errorAction() { - return (ctx) -> { - LOGGER.info("Error " + ctx.getSource().getId() + ctx.getException()); - }; - } - - @Bean - public Action initAction() { - return (ctx) -> { - LOGGER.info(ctx.getTarget().getId()); - }; - } -} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java deleted file mode 100644 index bb7859c683..0000000000 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.spring.stateMachine.config; - -import org.springframework.statemachine.listener.StateMachineListenerAdapter; -import org.springframework.statemachine.state.State; - -import java.util.logging.Logger; - -public class StateMachineListener extends StateMachineListenerAdapter { - - public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); - - @Override - public void stateChanged(State from, State to) { - LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java deleted file mode 100644 index 416da5f0fe..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; - -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.stateMachine.config.ForkJoinStateMachineConfiguration; - -public class ForkJoinStateMachineTest { - - @Test - public void whenForkStateEntered_thenMultipleSubStatesEntered() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - - boolean success = stateMachine.sendEvent("E1"); - - assertTrue(success); - - assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); - } - - @Test - public void whenAllConfiguredJoinEntryStatesAreEntered_thenTransitionToJoinState() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - - boolean success = stateMachine.sendEvent("E1"); - - assertTrue(success); - - assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); - - assertTrue(stateMachine.sendEvent("sub1")); - assertTrue(stateMachine.sendEvent("sub2")); - assertEquals("SJoin", stateMachine.getState().getId()); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java deleted file mode 100644 index 3557a63211..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; - -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.stateMachine.config.HierarchicalStateMachineConfiguration; - -public class HierarchicalStateMachineTest { - - @Test - public void whenTransitionToSubMachine_thenSubStateIsEntered() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(HierarchicalStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - - - assertEquals(Arrays.asList("SI", "SUB1"), stateMachine.getState().getIds()); - - stateMachine.sendEvent("se1"); - - assertEquals(Arrays.asList("SI", "SUB2"), stateMachine.getState().getIds()); - - stateMachine.sendEvent("s-end"); - - assertEquals(Arrays.asList("SI", "SUBEND"), stateMachine.getState().getIds()); - - stateMachine.sendEvent("end"); - - assertEquals(1, stateMachine.getState().getIds().size()); - assertEquals("SF", stateMachine.getState().getId()); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java deleted file mode 100644 index d0c1225c9b..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.stateMachine.config.JunctionStateMachineConfiguration; - -public class JunctionStateMachineTest { - - @Test - public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JunctionStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - - stateMachine.sendEvent("E1"); - Assert.assertEquals("low", stateMachine.getState().getId()); - - stateMachine.sendEvent("end"); - Assert.assertEquals("SF", stateMachine.getState().getId()); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java deleted file mode 100644 index 1fd7bd85f0..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; -import com.baeldung.spring.stateMachine.config.SimpleEnumStateMachineConfiguration; - -public class StateEnumMachineTest { - - private StateMachine stateMachine; - - @Before - public void setUp() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleEnumStateMachineConfiguration.class); - stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - } - - @Test - public void whenStateMachineConfiguredWithEnums_thenStateMachineAcceptsEnumEvents() { - assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.APPROVE)); - assertEquals(ApplicationReviewStates.PRINCIPAL_REVIEW, stateMachine.getState().getId()); - assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.REJECT)); - assertEquals(ApplicationReviewStates.REJECTED, stateMachine.getState().getId()); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java deleted file mode 100644 index cdd1e951e0..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.springframework.statemachine.StateMachine; -import org.springframework.statemachine.config.StateMachineBuilder; - -public class StateMachineBuilderTest { - - @Test - public void whenUseStateMachineBuilder_thenBuildSuccessAndMachineWorks() throws Exception { - StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); - builder.configureStates().withStates() - .initial("SI") - .state("S1") - .end("SF"); - - builder.configureTransitions() - .withExternal() - .source("SI").target("S1").event("E1") - .and().withExternal() - .source("S1").target("SF").event("E2"); - - StateMachine machine = builder.build(); - - machine.start(); - - machine.sendEvent("E1"); - assertEquals("S1", machine.getState().getId()); - - machine.sendEvent("E2"); - assertEquals("SF", machine.getState().getId()); - } -} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java deleted file mode 100644 index 1b442bf994..0000000000 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - -import com.baeldung.spring.stateMachine.config.SimpleStateMachineConfiguration; - -public class StateMachineTest { - - private StateMachine stateMachine; - - @Before - public void setUp() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleStateMachineConfiguration.class); - stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - } - - @Test - public void whenSimpleStringStateMachineEvents_thenEndState() { - assertEquals("SI", stateMachine.getState().getId()); - - stateMachine.sendEvent("E1"); - assertEquals("S1", stateMachine.getState().getId()); - - stateMachine.sendEvent("E2"); - assertEquals("S2", stateMachine.getState().getId()); - - stateMachine.sendEvent("end"); - assertEquals("SF", stateMachine.getState().getId()); - - } - - @Test - public void whenSimpleStringMachineActionState_thenActionExecuted() { - stateMachine.sendEvent("E3"); - assertEquals("S3", stateMachine.getState().getId()); - - stateMachine.sendEvent("E4"); - assertEquals("S4", stateMachine.getState().getId()); - assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount")); - } -} From 2aca6e085b1fddf6ba6a6fa621f1475aeaddd1b7 Mon Sep 17 00:00:00 2001 From: Yasin Date: Sat, 25 Mar 2017 01:57:45 +0530 Subject: [PATCH 176/291] BAEL-745 Quick Math.pow example (#1482) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements * BAEL-718 Quick intro to javatuples * merging pom from master * BAEL-722 Intro to JSONassert * BAEL-722 Intro to JSONassert Updated to 1.5.0 * BAEL-745 Quick Math.pow example --- .../java/com/baeldung/pow/PowerExample.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/pow/PowerExample.java diff --git a/core-java/src/main/java/com/baeldung/pow/PowerExample.java b/core-java/src/main/java/com/baeldung/pow/PowerExample.java new file mode 100644 index 0000000000..5be5376e6a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/pow/PowerExample.java @@ -0,0 +1,19 @@ +package com.baeldung.pow; + +import java.text.DecimalFormat; + +public class PowerExample { + + public static void main(String[] args) { + + int intResult = (int) Math.pow(2, 3); + System.out.println("Math.pow(2, 3) = " + intResult); + + double dblResult = Math.pow(4.2, 3); + System.out.println("Math.pow(4.2, 3) = " + Math.pow(4.2, 3)); + + DecimalFormat df = new DecimalFormat(".00"); + System.out.println("Math.pow(4.2, 3) rounded = " + df.format(dblResult)); + + } +} From c3764e3f443e8a47ddfe7932f8e5b5f1c91e7afe Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Sat, 25 Mar 2017 03:32:42 +0530 Subject: [PATCH 177/291] CORS in JAX-RS (#1484) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * changing banner format in plain text * Delete banner.txt~ * Delete b.txt~ * CORS in JAX-RS --- .../java/com/baeldung/filter/CorsFilter.java | 22 ++++ .../com/baeldung/server/MovieCrudService.java | 110 ++++++++++-------- resteasy/src/main/webapp/script.js | 16 +++ 3 files changed, 99 insertions(+), 49 deletions(-) create mode 100644 resteasy/src/main/java/com/baeldung/filter/CorsFilter.java create mode 100644 resteasy/src/main/webapp/script.js diff --git a/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java b/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java new file mode 100644 index 0000000000..266707fb9f --- /dev/null +++ b/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java @@ -0,0 +1,22 @@ +package com.baeldung.filter; + +import java.io.IOException; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.ext.Provider; + +@Provider +public class CorsFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + responseContext.getHeaders().add("Access-Control-Allow-Origin", "*"); + responseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); + responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true"); + responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); + } + +} diff --git a/resteasy/src/main/java/com/baeldung/server/MovieCrudService.java b/resteasy/src/main/java/com/baeldung/server/MovieCrudService.java index b7f3215f3f..5a623a2dc6 100644 --- a/resteasy/src/main/java/com/baeldung/server/MovieCrudService.java +++ b/resteasy/src/main/java/com/baeldung/server/MovieCrudService.java @@ -13,71 +13,83 @@ import java.util.stream.Collectors; @Path("/movies") public class MovieCrudService { - private Map inventory = new HashMap(); + private Map inventory = new HashMap(); - @GET - @Path("/getinfo") - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Movie movieByImdbId(@QueryParam("imdbId") String imdbId) { + @GET + @Path("/") + @Produces({ MediaType.TEXT_PLAIN }) + public Response index() { + return Response.status(200).header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization") + .header("Access-Control-Allow-Credentials", "true") + .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD").entity("").build(); + } - System.out.println("*** Calling getinfo for a given ImdbID***"); + @GET + @Path("/getinfo") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Movie movieByImdbId(@QueryParam("imdbId") String imdbId) { - if (inventory.containsKey(imdbId)) { - return inventory.get(imdbId); - } else - return null; - } + System.out.println("*** Calling getinfo for a given ImdbID***"); - @POST - @Path("/addmovie") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response addMovie(Movie movie) { + if (inventory.containsKey(imdbId)) { + return inventory.get(imdbId); + } else + return null; + } - System.out.println("*** Calling addMovie ***"); + @POST + @Path("/addmovie") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response addMovie(Movie movie) { - if (null != inventory.get(movie.getImdbId())) { - return Response.status(Response.Status.NOT_MODIFIED).entity("Movie is Already in the database.").build(); - } + System.out.println("*** Calling addMovie ***"); - inventory.put(movie.getImdbId(), movie); - return Response.status(Response.Status.CREATED).build(); - } + if (null != inventory.get(movie.getImdbId())) { + return Response.status(Response.Status.NOT_MODIFIED).entity("Movie is Already in the database.").build(); + } - @PUT - @Path("/updatemovie") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response updateMovie(Movie movie) { + inventory.put(movie.getImdbId(), movie); + return Response.status(Response.Status.CREATED).build(); + } - System.out.println("*** Calling updateMovie ***"); + @PUT + @Path("/updatemovie") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response updateMovie(Movie movie) { - if (null == inventory.get(movie.getImdbId())) { - return Response.status(Response.Status.NOT_MODIFIED).entity("Movie is not in the database.\nUnable to Update").build(); - } + System.out.println("*** Calling updateMovie ***"); - inventory.put(movie.getImdbId(), movie); - return Response.status(Response.Status.OK).build(); - } + if (null == inventory.get(movie.getImdbId())) { + return Response.status(Response.Status.NOT_MODIFIED) + .entity("Movie is not in the database.\nUnable to Update").build(); + } - @DELETE - @Path("/deletemovie") - public Response deleteMovie(@QueryParam("imdbId") String imdbId) { + inventory.put(movie.getImdbId(), movie); + return Response.status(Response.Status.OK).build(); + } - System.out.println("*** Calling deleteMovie ***"); + @DELETE + @Path("/deletemovie") + public Response deleteMovie(@QueryParam("imdbId") String imdbId) { - if (null == inventory.get(imdbId)) { - return Response.status(Response.Status.NOT_FOUND).entity("Movie is not in the database.\nUnable to Delete").build(); - } + System.out.println("*** Calling deleteMovie ***"); - inventory.remove(imdbId); - return Response.status(Response.Status.OK).build(); - } + if (null == inventory.get(imdbId)) { + return Response.status(Response.Status.NOT_FOUND).entity("Movie is not in the database.\nUnable to Delete") + .build(); + } - @GET - @Path("/listmovies") - @Produces({ "application/json" }) - public List listMovies() { + inventory.remove(imdbId); + return Response.status(Response.Status.OK).build(); + } - return inventory.values().stream().collect(Collectors.toCollection(ArrayList::new)); - } + @GET + @Path("/listmovies") + @Produces({ "application/json" }) + public List listMovies() { + + return inventory.values().stream().collect(Collectors.toCollection(ArrayList::new)); + } } diff --git a/resteasy/src/main/webapp/script.js b/resteasy/src/main/webapp/script.js new file mode 100644 index 0000000000..88198887b0 --- /dev/null +++ b/resteasy/src/main/webapp/script.js @@ -0,0 +1,16 @@ +function call(url, type, data) { + var request = $.ajax({ + url : url, + method : "GET", + data : (data) ? JSON.stringify(data) : "", + dataType : type + }); + + request.done(function(resp) { + console.log(resp); + }); + + request.fail(function(jqXHR, textStatus) { + console.log("Request failed: " + textStatus); + }); +}; \ No newline at end of file From 9472f0dd65885d49f365256e88c594009a460f0a Mon Sep 17 00:00:00 2001 From: mujahid Date: Sat, 25 Mar 2017 15:18:20 +0800 Subject: [PATCH 178/291] BAEL-347 - change solr-fulltext-search to solr (#1462) * solr-fulltext-search module created * solr-fulltext-search modue created * solr-fulltext-search change s * pom changes merged from upstream * removed integration tests from mvn build * Refactoring test class * removed test profile * module solr-fulltext-search changed to solr * module solr added in parent pom * delete file * removed unused file, changed test to default solr port --- pom.xml | 2 +- .../solr/fulltexh/search/model/Product.java | 5 - .../search/service/SolrSearchService.java | 5 - .../ItemSearchServiceIntegrationTest.java | 374 ------------------ {solr-fulltext-search => solr}/pom.xml | 4 +- .../solr/fulltext/search/model/Item.java | 0 .../search/service/ItemSearchService.java | 0 .../search/service/ItemSearchServiceImpl.java | 0 .../service/ItemSearchServiceLiveTest.java | 2 +- 9 files changed, 4 insertions(+), 388 deletions(-) delete mode 100644 solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/model/Product.java delete mode 100644 solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/service/SolrSearchService.java delete mode 100644 solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java rename {solr-fulltext-search => solr}/pom.xml (95%) rename {solr-fulltext-search => solr}/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java (100%) rename {solr-fulltext-search => solr}/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java (100%) rename {solr-fulltext-search => solr}/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java (100%) rename {solr-fulltext-search => solr}/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java (99%) diff --git a/pom.xml b/pom.xml index 791430ba0e..4796a11ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -109,7 +109,7 @@ rxjava selenium-junit-testng - solr-fulltext-search + solr spark-java spring-akka diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/model/Product.java b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/model/Product.java deleted file mode 100644 index b5fb334282..0000000000 --- a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/model/Product.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.solr.fulltexh.search.model; - -public class Product { - -} diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/service/SolrSearchService.java b/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/service/SolrSearchService.java deleted file mode 100644 index aa511f0e1b..0000000000 --- a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltexh/search/service/SolrSearchService.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.baeldung.solr.fulltexh.search.service; - -public interface SolrSearchService { - -} diff --git a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java b/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java deleted file mode 100644 index 94661ffc2e..0000000000 --- a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceIntegrationTest.java +++ /dev/null @@ -1,374 +0,0 @@ -package com.baeldung.solr.fulltext.search.service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.List; -import java.util.Map; - -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrQuery; -import org.apache.solr.client.solrj.impl.HttpSolrClient; -import org.apache.solr.client.solrj.response.FacetField.Count; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.response.RangeFacet; -import org.apache.solr.client.solrj.response.SpellCheckResponse; -import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; -import org.apache.solr.client.solrj.response.SuggesterResponse; -import org.apache.solr.common.SolrDocument; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.baeldung.solr.fulltext.search.model.Item; - -public class ItemSearchServiceIntegrationTest { - - private static SolrClient solrClient; - private static ItemSearchService itemSearchService; - private static final String solrUrl = "http://localhost:8987/solr/item"; - - @BeforeClass - public static void initBeans() throws Exception { - solrClient = new HttpSolrClient.Builder(solrUrl).build(); - itemSearchService = new ItemSearchServiceImpl(solrClient); - - solrClient.commit(); - } - - @Before - public void clearSolrData() throws Exception { - solrClient.deleteByQuery("*:*"); - } - - @Test - public void whenIndexing_thenAvailableOnRetrieval() throws Exception { - itemSearchService.index("hm0001", "Washing Machine", "Home Appliances", 450f); - final SolrDocument indexedDoc = solrClient.getById("hm0001"); - assertEquals("hm0001", indexedDoc.get("id")); - } - - @Test - public void whenIndexingBean_thenAvailableOnRetrieval() throws Exception { - Item item = new Item(); - item.setId("hm0002"); - item.setCategory("Televisions"); - item.setDescription("LED TV 32"); - item.setPrice(500); - itemSearchService.indexBean(item); - } - - @Test - public void whenSearchingByBasicQuery_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("brand1"); - query.setStart(0); - query.setRows(10); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(3, items.size()); - - } - - @Test - public void whenSearchingWithWildCard_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "LED TV 32", "Brand1 Home Appliances", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("*rand?"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(3, items.size()); - } - - @Test - public void whenSearchingWithLogicalOperators_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "Brand2 LED TV 32", "Washing Appliances", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("brand1 AND (Washing OR Refrigerator)"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(2, items.size()); - } - - @Test - public void whenSearchingWithFields_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("0003", "Brand2 LED TV 32", "Brand1 Washing Home Appliances", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("description:Brand* AND category:*Washing*"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(1, items.size()); - } - - @Test - public void whenSearchingWithPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("washing MachIne"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(2, items.size()); - } - - @Test - public void whenSearchingWithRealPhrase_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("\"washing machine\""); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(1, items.size()); - } - - @Test - public void whenSearchingPhraseWithProximity_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 450f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 450f); - itemSearchService.index("hm0003", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("\"Washing equipment\"~2"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(1, items.size()); - } - - @Test - public void whenSearchingWithPriceRange_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("price:[100 TO 300]"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(3, items.size()); - } - - @Test - public void whenSearchingWithPriceRangeInclusiveExclusive_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Dishwasher", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 450f); - - SolrQuery query = new SolrQuery(); - query.setQuery("price:{100 TO 300]"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(2, items.size()); - } - - @Test - public void whenSearchingWithFilterQuery_thenAllMatchingItemsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing tools and equipment ", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("price:[100 TO 300]"); - query.addFilterQuery("description:Brand1", "category:Home Appliances"); - - QueryResponse response = solrClient.query(query); - List items = response.getBeans(Item.class); - - assertEquals(2, items.size()); - } - - @Test - public void whenSearchingWithFacetFields_thenAllMatchingFacetsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("*:*"); - query.addFacetField("category"); - - QueryResponse response = solrClient.query(query); - List facetResults = response.getFacetField("category").getValues(); - - assertEquals(2, facetResults.size()); - - for (Count count : facetResults) { - if ("categorya".equalsIgnoreCase(count.getName())) { - assertEquals(2, count.getCount()); - } else if ("categoryb".equalsIgnoreCase(count.getName())) { - assertEquals(2, count.getCount()); - } else { - fail("unexpected category"); - } - } - } - - @Test - public void whenSearchingWithFacetQuery_thenAllMatchingFacetsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("*:*"); - - query.addFacetQuery("Washing OR Refrigerator"); - query.addFacetQuery("Brand2"); - - QueryResponse response = solrClient.query(query); - Map facetQueryMap = response.getFacetQuery(); - - assertEquals(2, facetQueryMap.size()); - - for (Map.Entry entry : facetQueryMap.entrySet()) { - String facetQuery = entry.getKey(); - - if ("Washing OR Refrigerator".equals(facetQuery)) { - assertEquals(Integer.valueOf(2), entry.getValue()); - } else if ("Brand2".equals(facetQuery)) { - assertEquals(Integer.valueOf(2), entry.getValue()); - } else { - fail("unexpected query"); - } - - } - } - - @Test - public void whenSearchingWithFacetRange_thenAllMatchingFacetsShouldAvialble() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "CategoryA", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "CategoryA", 125f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "CategoryB", 150f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "CategoryB", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("*:*"); - - query.addNumericRangeFacet("price", 100, 275, 25); - - QueryResponse response = solrClient.query(query); - List rangeFacets = response.getFacetRanges().get(0).getCounts(); - - assertEquals(7, rangeFacets.size()); - } - - @Test - public void whenSearchingWithHitHighlighting_thenKeywordsShouldBeHighlighted() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("Appliances"); - query.setHighlight(true); - query.addHighlightField("category"); - query.setHighlightSimplePre(""); - query.setHighlightSimplePost(""); - QueryResponse response = solrClient.query(query); - - Map>> hitHighlightedMap = response.getHighlighting(); - Map> highlightedFieldMap = hitHighlightedMap.get("hm0001"); - List highlightedList = highlightedFieldMap.get("category"); - String highLightedText = highlightedList.get(0); - - assertEquals("Home Appliances", highLightedText); - - } - - @Test - public void whenSearchingWithKeywordWithMistake_thenSpellingSuggestionsShouldBeReturned() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); - - SolrQuery query = new SolrQuery(); - query.setQuery("hme"); - query.set("spellcheck", "on"); - QueryResponse response = solrClient.query(query); - - SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse(); - - assertEquals(false, spellCheckResponse.isCorrectlySpelled()); - - Suggestion suggestion = spellCheckResponse.getSuggestions().get(0); - - assertEquals("hme", suggestion.getToken()); - - List alternatives = suggestion.getAlternatives(); - String alternative = alternatives.get(0); - - assertEquals("home", alternative); - } - - @Test - public void whenSearchingWithIncompleteKeyword_thenKeywordSuggestionsShouldBeReturned() throws Exception { - itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); - itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); - itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); - itemSearchService.index("hm0004", "Brand2 Dishwasher", "Home washing equipments", 250f); - - SolrQuery query = new SolrQuery(); - query.setRequestHandler("/suggest"); - query.set("suggest", "true"); - query.set("suggest.build", "true"); - query.set("suggest.dictionary", "mySuggester"); - query.set("suggest.q", "Hom"); - QueryResponse response = solrClient.query(query); - - SuggesterResponse suggesterResponse = response.getSuggesterResponse(); - Map> suggestedTerms = suggesterResponse.getSuggestedTerms(); - List suggestions = suggestedTerms.get("mySuggester"); - - assertEquals(2, suggestions.size()); - - for (String term : suggestions) { - if (!"Home Appliances".equals(term) && !"Home washing equipments".equals(term)) { - fail("Unexpected suggestions"); - } - } - - } - -} diff --git a/solr-fulltext-search/pom.xml b/solr/pom.xml similarity index 95% rename from solr-fulltext-search/pom.xml rename to solr/pom.xml index 5b2950d64c..e784d87157 100644 --- a/solr-fulltext-search/pom.xml +++ b/solr/pom.xml @@ -3,10 +3,10 @@ 4.0.0 com.baeldung - solr-fulltext-search + solr 0.0.1-SNAPSHOT jar - solr-fulltext-search + solr diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java b/solr/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java similarity index 100% rename from solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java rename to solr/src/main/java/com/baeldung/solr/fulltext/search/model/Item.java diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java b/solr/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java similarity index 100% rename from solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java rename to solr/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchService.java diff --git a/solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java b/solr/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java similarity index 100% rename from solr-fulltext-search/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java rename to solr/src/main/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceImpl.java diff --git a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java b/solr/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java similarity index 99% rename from solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java rename to solr/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java index 1489d40787..3704f4c34c 100644 --- a/solr-fulltext-search/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java +++ b/solr/src/test/java/com/baeldung/solr/fulltext/search/service/ItemSearchServiceLiveTest.java @@ -26,7 +26,7 @@ public class ItemSearchServiceLiveTest { private static SolrClient solrClient; private static ItemSearchService itemSearchService; - private static final String solrUrl = "http://localhost:8987/solr/item"; + private static final String solrUrl = "http://localhost:8983/solr/item"; @BeforeClass public static void initBeans() throws Exception { From b6e271f1f0f111e02ae6141918fb32cae265067f Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 25 Mar 2017 09:25:51 +0100 Subject: [PATCH 179/291] spring-custom-aop -> spring-aop (#1489) --- pom.xml | 1 + {spring-custom-aop => spring-aop}/pom.xml | 0 .../src/main/java/org/baeldung/Application.java | 0 .../src/main/java/org/baeldung/ExampleAspect.java | 0 .../src/main/java/org/baeldung/LogExecutionTime.java | 0 .../src/main/java/org/baeldung/Service.java | 0 .../src/test/java/org/baeldung/CustomAnnotationTest.java | 0 7 files changed, 1 insertion(+) rename {spring-custom-aop => spring-aop}/pom.xml (100%) rename {spring-custom-aop => spring-aop}/src/main/java/org/baeldung/Application.java (100%) rename {spring-custom-aop => spring-aop}/src/main/java/org/baeldung/ExampleAspect.java (100%) rename {spring-custom-aop => spring-aop}/src/main/java/org/baeldung/LogExecutionTime.java (100%) rename {spring-custom-aop => spring-aop}/src/main/java/org/baeldung/Service.java (100%) rename {spring-custom-aop => spring-aop}/src/test/java/org/baeldung/CustomAnnotationTest.java (100%) diff --git a/pom.xml b/pom.xml index 4796a11ac4..187ff60dd2 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,7 @@ spring-cloud spring-core spring-cucumber + spring-aop spring-data-cassandra spring-data-couchbase-2 spring-data-dynamodb diff --git a/spring-custom-aop/pom.xml b/spring-aop/pom.xml similarity index 100% rename from spring-custom-aop/pom.xml rename to spring-aop/pom.xml diff --git a/spring-custom-aop/src/main/java/org/baeldung/Application.java b/spring-aop/src/main/java/org/baeldung/Application.java similarity index 100% rename from spring-custom-aop/src/main/java/org/baeldung/Application.java rename to spring-aop/src/main/java/org/baeldung/Application.java diff --git a/spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java b/spring-aop/src/main/java/org/baeldung/ExampleAspect.java similarity index 100% rename from spring-custom-aop/src/main/java/org/baeldung/ExampleAspect.java rename to spring-aop/src/main/java/org/baeldung/ExampleAspect.java diff --git a/spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java b/spring-aop/src/main/java/org/baeldung/LogExecutionTime.java similarity index 100% rename from spring-custom-aop/src/main/java/org/baeldung/LogExecutionTime.java rename to spring-aop/src/main/java/org/baeldung/LogExecutionTime.java diff --git a/spring-custom-aop/src/main/java/org/baeldung/Service.java b/spring-aop/src/main/java/org/baeldung/Service.java similarity index 100% rename from spring-custom-aop/src/main/java/org/baeldung/Service.java rename to spring-aop/src/main/java/org/baeldung/Service.java diff --git a/spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java b/spring-aop/src/test/java/org/baeldung/CustomAnnotationTest.java similarity index 100% rename from spring-custom-aop/src/test/java/org/baeldung/CustomAnnotationTest.java rename to spring-aop/src/test/java/org/baeldung/CustomAnnotationTest.java From efc2043e5285cfa3067a86b2cd1c19c7bacc73d3 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 25 Mar 2017 10:37:00 +0100 Subject: [PATCH 180/291] KafkaProducerConfig refactor (#1488) --- pom.xml | 1 + .../spring/kafka/KafkaProducerConfig.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 187ff60dd2..5c85e94546 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,7 @@ spring-jms spring-jooq spring-jpa + spring-kafka spring-katharsis spring-ldap spring-mockito diff --git a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java index 84d57c9e92..7e2527b36e 100644 --- a/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java +++ b/spring-kafka/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java @@ -1,8 +1,5 @@ package com.baeldung.spring.kafka; -import java.util.HashMap; -import java.util.Map; - import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.beans.factory.annotation.Value; @@ -13,6 +10,9 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; import org.springframework.kafka.support.serializer.JsonSerializer; +import java.util.HashMap; +import java.util.Map; + @Configuration public class KafkaProducerConfig { @@ -21,30 +21,30 @@ public class KafkaProducerConfig { @Bean public ProducerFactory producerFactory() { - Map configProps = new HashMap(); + Map configProps = new HashMap<>(); configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); - return new DefaultKafkaProducerFactory(configProps); + return new DefaultKafkaProducerFactory<>(configProps); } @Bean public KafkaTemplate kafkaTemplate() { - return new KafkaTemplate(producerFactory()); + return new KafkaTemplate<>(producerFactory()); } @Bean public ProducerFactory greetingProducerFactory() { - Map configProps = new HashMap(); + Map configProps = new HashMap<>(); configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress); configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); - return new DefaultKafkaProducerFactory(configProps); + return new DefaultKafkaProducerFactory<>(configProps); } @Bean public KafkaTemplate greetingKafkaTemplate() { - return new KafkaTemplate(greetingProducerFactory()); + return new KafkaTemplate<>(greetingProducerFactory()); } } From 669f4d6dce4d528dd6c8ad7382ebd33c2b6a71db Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 25 Mar 2017 11:00:16 +0100 Subject: [PATCH 181/291] Further build improvements (#1486) --- javaslang/pom.xml | 12 ++++++++++++ ...st.java => PropertyBasedLongRunningUnitTest.java} | 2 +- metrics/pom.xml | 12 ++++++++++++ ...{MetricsTest.java => MetricsIntegrationTest.java} | 2 +- 4 files changed, 26 insertions(+), 2 deletions(-) rename javaslang/src/test/java/com/baeldung/javaslang/{PropertyBasedTest.java => PropertyBasedLongRunningUnitTest.java} (97%) rename metrics/src/test/java/com/baeldung/metrics/core/{MetricsTest.java => MetricsIntegrationTest.java} (99%) diff --git a/javaslang/pom.xml b/javaslang/pom.xml index 941aac0802..3770cce548 100644 --- a/javaslang/pom.xml +++ b/javaslang/pom.xml @@ -44,6 +44,18 @@ 1.8 + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + + true + + \ No newline at end of file diff --git a/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedLongRunningUnitTest.java similarity index 97% rename from javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java rename to javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedLongRunningUnitTest.java index 43f3d6e6a0..2bbc92563e 100644 --- a/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedTest.java +++ b/javaslang/src/test/java/com/baeldung/javaslang/PropertyBasedLongRunningUnitTest.java @@ -11,7 +11,7 @@ import java.util.function.Predicate; import static javaslang.API.*; -public class PropertyBasedTest { +public class PropertyBasedLongRunningUnitTest { private static Predicate divisibleByTwo = i -> i % 2 == 0; private static Predicate divisibleByFive = i -> i % 5 == 0; diff --git a/metrics/pom.xml b/metrics/pom.xml index 0f5cb2f135..6111ebf30b 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -69,6 +69,18 @@ ${maven.compiler.target}
+ + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + + true + +
diff --git a/metrics/src/test/java/com/baeldung/metrics/core/MetricsTest.java b/metrics/src/test/java/com/baeldung/metrics/core/MetricsIntegrationTest.java similarity index 99% rename from metrics/src/test/java/com/baeldung/metrics/core/MetricsTest.java rename to metrics/src/test/java/com/baeldung/metrics/core/MetricsIntegrationTest.java index e876de6e65..352911f1e1 100644 --- a/metrics/src/test/java/com/baeldung/metrics/core/MetricsTest.java +++ b/metrics/src/test/java/com/baeldung/metrics/core/MetricsIntegrationTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -public class MetricsTest { +public class MetricsIntegrationTest { @Test public void whenMarkMeter_thenCorrectRates() throws InterruptedException { Meter meter = new Meter(); From 21f9df63304a695cdcbb714fa1138b2b610d6751 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Sat, 25 Mar 2017 11:14:09 +0100 Subject: [PATCH 182/291] Bael 518 protobuffer (#1400) * BEEL-518 code for protobuf article * BEEL-518 add generated protobuf class * BEEL-550 use newest version of protobuff * BAEL-518 Small refactoring in protobuffer module * BEEL-518 simpler protobuf example * BEEL-518 proper package --- book | 0 ...638124c-9a1b-4d25-8fce-cc223d472e77.events | Bin 0 -> 663 bytes ...2ba9cbe-1a44-428e-a710-13b1bdc67c4b.events | Bin 0 -> 675 bytes ...f420ffc-0c3b-403e-bb8c-66cf499c773e.events | Bin 0 -> 714 bytes ...72a057b-adea-4c69-83a0-0431318823e7.events | Bin 0 -> 714 bytes .../baeldung/protobuf/AddressBookProtos.java | 1488 +++-------------- .../src/main/resources/addressbook.proto | 13 +- .../com/baeldung/protobuf/ProtobufTest.java | 21 +- .../cache/2d9345a30d2cc31bb3091d70a8ef6c18.0 | 24 + .../cache/2d9345a30d2cc31bb3091d70a8ef6c18.1 | 39 + .../cache/4b217e04ba52215f3a6b64d28f6729c6.0 | 13 + .../cache/4b217e04ba52215f3a6b64d28f6729c6.1 | 7 + spring-rest/src/test/resources/cache/journal | 12 + 13 files changed, 334 insertions(+), 1283 deletions(-) create mode 100644 book create mode 100644 events/MessagesAggregate/0638124c-9a1b-4d25-8fce-cc223d472e77.events create mode 100644 events/MessagesAggregate/d2ba9cbe-1a44-428e-a710-13b1bdc67c4b.events create mode 100644 events/ToDoItem/bf420ffc-0c3b-403e-bb8c-66cf499c773e.events create mode 100644 events/ToDoItem/e72a057b-adea-4c69-83a0-0431318823e7.events create mode 100644 spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.0 create mode 100644 spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.1 create mode 100644 spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.0 create mode 100644 spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.1 create mode 100644 spring-rest/src/test/resources/cache/journal diff --git a/book b/book new file mode 100644 index 0000000000..e69de29bb2 diff --git a/events/MessagesAggregate/0638124c-9a1b-4d25-8fce-cc223d472e77.events b/events/MessagesAggregate/0638124c-9a1b-4d25-8fce-cc223d472e77.events new file mode 100644 index 0000000000000000000000000000000000000000..d3ce8b9cea0dd432ac369a37c2281c78d9b98a7e GIT binary patch literal 663 zcmbV|O-jT-5QW>lR}iwuMzoUZpQL+2la094g?NEVcV!%K5-_dI0X&Q6bPV`|2s5#k zkM~|ZJ|S`wRy{gK;D8;Ns1!I899XF=>B?F{Db5s13#b9>d#M{$Hxi55sSA`1qR6q< zPAU^%MRG2w!1aM41f_H|R^De`pnD?D4^6&f`hoWKAlfhgLaqndeHZ@*_YUaJ B!ZiQ@ literal 0 HcmV?d00001 diff --git a/events/MessagesAggregate/d2ba9cbe-1a44-428e-a710-13b1bdc67c4b.events b/events/MessagesAggregate/d2ba9cbe-1a44-428e-a710-13b1bdc67c4b.events new file mode 100644 index 0000000000000000000000000000000000000000..2ab0ec469f90efe0f09ac43380e620738125a0ce GIT binary patch literal 675 zcmbV|%}T>S6otpVuOMX6O|dtbJ2TECVTcP6+_;gxz@3@fT4)<+Qf>D>kxytW_=5Zfq;`tB*0x5>wYHZMYbnJj zsX$c>3`oX+Q6&R8lz=*5NYT1zg7~;eY*%?8UZ(AOp3|;f=lsO$zRT~q>uAn58>XJq z?R$6_z4}uojbEhZFGRi=ioWMv-`w$X*-o;@_BmU0*}mOwvPApqtcI~K4h>(N#4vE5 z`xW;DiFzs;Ax2t87g9)2&YT7lm4b>Z1IcKL<)Ar*@VjYa^gm3WiSaSy2c~bDUyf@2 P?4RiPsJpMnKgGQPZ1>2E literal 0 HcmV?d00001 diff --git a/events/ToDoItem/bf420ffc-0c3b-403e-bb8c-66cf499c773e.events b/events/ToDoItem/bf420ffc-0c3b-403e-bb8c-66cf499c773e.events new file mode 100644 index 0000000000000000000000000000000000000000..d805fc253e397456a33c8b6b1d5de5b42af14043 GIT binary patch literal 714 zcmbV|zfQw25QojqD0Xq?%h7JV7VWa4wZIZDKbZ8x1G`)uw4yLanf^6zW@SR)}or zljN9E01U!|L_y$v7eJ|yq%lEjLF~66b z`0zFTPJP(3GQBN1=5_2(;j;D5v5j;H`(amxJoS%6aZ&Oj=0$lP4z~WgwDoy7^AFc{ zq~ajD;_9BUWowLYNlS==&&Fbh(3#YL);uXqE^5>LuU(_KK>HOtfjN)6Eggw}KSBIa O>O%GB!p#bgm3{(Qui1M5 literal 0 HcmV?d00001 diff --git a/events/ToDoItem/e72a057b-adea-4c69-83a0-0431318823e7.events b/events/ToDoItem/e72a057b-adea-4c69-83a0-0431318823e7.events new file mode 100644 index 0000000000000000000000000000000000000000..3d67b74ced4494b9f3af4f38b6bef9622c565329 GIT binary patch literal 714 zcmbWzJx&8L5CveCo(s|90)j+6E}nP~`%%_5>nj*HK~+N8vP_jRk>3B#IU(=vG1IB*R{7Y%t8QQRn$EuaQ$R#GmsTG+NS5^qs15XGEZ zMQGa|C^3PFjR&U*0gaYgI;S+Z;&&kCq3VgZ>1BMX=q-;Gzw%fP)hgfTW#Qp&&r~=) ze7%0BKEhdrepeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - java.util.List - getPhonesList(); + java.util.List + getNumbersList(); /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - AddressBookProtos.Person.PhoneNumber getPhones(int index); + int getNumbersCount(); /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - int getPhonesCount(); + java.lang.String getNumbers(int index); /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - java.util.List - getPhonesOrBuilderList(); - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( - int index); + com.google.protobuf.ByteString + getNumbersBytes(int index); } /** @@ -108,7 +102,7 @@ public final class AddressBookProtos { name_ = ""; id_ = 0; email_ = ""; - phones_ = java.util.Collections.emptyList(); + numbers_ = com.google.protobuf.LazyStringArrayList.EMPTY; } @java.lang.Override @@ -158,12 +152,12 @@ public final class AddressBookProtos { break; } case 34: { + com.google.protobuf.ByteString bs = input.readBytes(); if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) { - phones_ = new java.util.ArrayList(); + numbers_ = new com.google.protobuf.LazyStringArrayList(); mutable_bitField0_ |= 0x00000008; } - phones_.add( - input.readMessage(AddressBookProtos.Person.PhoneNumber.PARSER, extensionRegistry)); + numbers_.add(bs); break; } } @@ -175,7 +169,7 @@ public final class AddressBookProtos { e).setUnfinishedMessage(this); } finally { if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) { - phones_ = java.util.Collections.unmodifiableList(phones_); + numbers_ = numbers_.getUnmodifiableView(); } this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); @@ -184,819 +178,14 @@ public final class AddressBookProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return AddressBookProtos.internal_static_protobuf_Person_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_Person_descriptor; } protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable .ensureFieldAccessorsInitialized( - AddressBookProtos.Person.class, AddressBookProtos.Person.Builder.class); - } - - /** - * Protobuf enum {@code protobuf.Person.PhoneType} - */ - public enum PhoneType - implements com.google.protobuf.ProtocolMessageEnum { - /** - * MOBILE = 0; - */ - MOBILE(0), - /** - * HOME = 1; - */ - HOME(1), - /** - * WORK = 2; - */ - WORK(2),; - - /** - * MOBILE = 0; - */ - public static final int MOBILE_VALUE = 0; - /** - * HOME = 1; - */ - public static final int HOME_VALUE = 1; - /** - * WORK = 2; - */ - public static final int WORK_VALUE = 2; - - - public final int getNumber() { - return value; - } - - /** - * @deprecated Use {@link #forNumber(int)} instead. - */ - @java.lang.Deprecated - public static PhoneType valueOf(int value) { - return forNumber(value); - } - - public static PhoneType forNumber(int value) { - switch (value) { - case 0: - return MOBILE; - case 1: - return HOME; - case 2: - return WORK; - default: - return null; - } - } - - public static com.google.protobuf.Internal.EnumLiteMap - internalGetValueMap() { - return internalValueMap; - } - - private static final com.google.protobuf.Internal.EnumLiteMap< - PhoneType> internalValueMap = - new com.google.protobuf.Internal.EnumLiteMap() { - public PhoneType findValueByNumber(int number) { - return PhoneType.forNumber(number); - } - }; - - public final com.google.protobuf.Descriptors.EnumValueDescriptor - getValueDescriptor() { - return getDescriptor().getValues().get(ordinal()); - } - - public final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptorForType() { - return getDescriptor(); - } - - public static final com.google.protobuf.Descriptors.EnumDescriptor - getDescriptor() { - return AddressBookProtos.Person.getDescriptor().getEnumTypes().get(0); - } - - private static final PhoneType[] VALUES = values(); - - public static PhoneType valueOf( - com.google.protobuf.Descriptors.EnumValueDescriptor desc) { - if (desc.getType() != getDescriptor()) { - throw new java.lang.IllegalArgumentException( - "EnumValueDescriptor is not for this type."); - } - return VALUES[desc.getIndex()]; - } - - private final int value; - - private PhoneType(int value) { - this.value = value; - } - - // @@protoc_insertion_point(enum_scope:protobuf.Person.PhoneType) - } - - public interface PhoneNumberOrBuilder extends - // @@protoc_insertion_point(interface_extends:protobuf.Person.PhoneNumber) - com.google.protobuf.MessageOrBuilder { - - /** - * required string number = 1; - */ - boolean hasNumber(); - - /** - * required string number = 1; - */ - java.lang.String getNumber(); - - /** - * required string number = 1; - */ - com.google.protobuf.ByteString - getNumberBytes(); - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - boolean hasType(); - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - AddressBookProtos.Person.PhoneType getType(); - } - - /** - * Protobuf type {@code protobuf.Person.PhoneNumber} - */ - public static final class PhoneNumber extends - com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:protobuf.Person.PhoneNumber) - PhoneNumberOrBuilder { - // Use PhoneNumber.newBuilder() to construct. - private PhoneNumber(com.google.protobuf.GeneratedMessageV3.Builder builder) { - super(builder); - } - - private PhoneNumber() { - number_ = ""; - type_ = 1; - } - - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - - private PhoneNumber( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - this(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 10: { - com.google.protobuf.ByteString bs = input.readBytes(); - bitField0_ |= 0x00000001; - number_ = bs; - break; - } - case 16: { - int rawValue = input.readEnum(); - AddressBookProtos.Person.PhoneType value = AddressBookProtos.Person.PhoneType.valueOf(rawValue); - if (value == null) { - unknownFields.mergeVarintField(2, rawValue); - } else { - bitField0_ |= 0x00000002; - type_ = rawValue; - } - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e).setUnfinishedMessage(this); - } finally { - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable - .ensureFieldAccessorsInitialized( - AddressBookProtos.Person.PhoneNumber.class, AddressBookProtos.Person.PhoneNumber.Builder.class); - } - - private int bitField0_; - public static final int NUMBER_FIELD_NUMBER = 1; - private volatile java.lang.Object number_; - - /** - * required string number = 1; - */ - public boolean hasNumber() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - - /** - * required string number = 1; - */ - public java.lang.String getNumber() { - java.lang.Object ref = number_; - if (ref instanceof java.lang.String) { - return (java.lang.String) ref; - } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - number_ = s; - } - return s; - } - } - - /** - * required string number = 1; - */ - public com.google.protobuf.ByteString - getNumberBytes() { - java.lang.Object ref = number_; - if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - number_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - public static final int TYPE_FIELD_NUMBER = 2; - private int type_; - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public boolean hasType() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public AddressBookProtos.Person.PhoneType getType() { - AddressBookProtos.Person.PhoneType result = AddressBookProtos.Person.PhoneType.valueOf(type_); - return result == null ? AddressBookProtos.Person.PhoneType.HOME : result; - } - - private byte memoizedIsInitialized = -1; - - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; - - if (!hasNumber()) { - memoizedIsInitialized = 0; - return false; - } - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - if (((bitField0_ & 0x00000001) == 0x00000001)) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, number_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeEnum(2, type_); - } - unknownFields.writeTo(output); - } - - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, number_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeEnumSize(2, type_); - } - size += unknownFields.getSerializedSize(); - memoizedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - - @java.lang.Override - public boolean equals(final java.lang.Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof AddressBookProtos.Person.PhoneNumber)) { - return super.equals(obj); - } - AddressBookProtos.Person.PhoneNumber other = (AddressBookProtos.Person.PhoneNumber) obj; - - boolean result = true; - result = result && (hasNumber() == other.hasNumber()); - if (hasNumber()) { - result = result && getNumber() - .equals(other.getNumber()); - } - result = result && (hasType() == other.hasType()); - if (hasType()) { - result = result && type_ == other.type_; - } - result = result && unknownFields.equals(other.unknownFields); - return result; - } - - @java.lang.Override - public int hashCode() { - if (memoizedHashCode != 0) { - return memoizedHashCode; - } - int hash = 41; - hash = (19 * hash) + getDescriptorForType().hashCode(); - if (hasNumber()) { - hash = (37 * hash) + NUMBER_FIELD_NUMBER; - hash = (53 * hash) + getNumber().hashCode(); - } - if (hasType()) { - hash = (37 * hash) + TYPE_FIELD_NUMBER; - hash = (53 * hash) + type_; - } - hash = (29 * hash) + unknownFields.hashCode(); - memoizedHashCode = hash; - return hash; - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public static AddressBookProtos.Person.PhoneNumber parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input); - } - - public static AddressBookProtos.Person.PhoneNumber parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseDelimitedWithIOException(PARSER, input, extensionRegistry); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input); - } - - public static AddressBookProtos.Person.PhoneNumber parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageV3 - .parseWithIOException(PARSER, input, extensionRegistry); - } - - public Builder newBuilderForType() { - return newBuilder(); - } - - public static Builder newBuilder() { - return DEFAULT_INSTANCE.toBuilder(); - } - - public static Builder newBuilder(AddressBookProtos.Person.PhoneNumber prototype) { - return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); - } - - public Builder toBuilder() { - return this == DEFAULT_INSTANCE - ? new Builder() : new Builder().mergeFrom(this); - } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - - /** - * Protobuf type {@code protobuf.Person.PhoneNumber} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:protobuf.Person.PhoneNumber) - AddressBookProtos.Person.PhoneNumberOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; - } - - protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable - .ensureFieldAccessorsInitialized( - AddressBookProtos.Person.PhoneNumber.class, AddressBookProtos.Person.PhoneNumber.Builder.class); - } - - // Construct using AddressBookProtos.Person.PhoneNumber.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessageV3 - .alwaysUseFieldBuilders) { - } - } - - public Builder clear() { - super.clear(); - number_ = ""; - bitField0_ = (bitField0_ & ~0x00000001); - type_ = 1; - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return AddressBookProtos.internal_static_protobuf_Person_PhoneNumber_descriptor; - } - - public AddressBookProtos.Person.PhoneNumber getDefaultInstanceForType() { - return AddressBookProtos.Person.PhoneNumber.getDefaultInstance(); - } - - public AddressBookProtos.Person.PhoneNumber build() { - AddressBookProtos.Person.PhoneNumber result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public AddressBookProtos.Person.PhoneNumber buildPartial() { - AddressBookProtos.Person.PhoneNumber result = new AddressBookProtos.Person.PhoneNumber(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.number_ = number_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.type_ = type_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder clone() { - return (Builder) super.clone(); - } - - public Builder setField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.setField(field, value); - } - - public Builder clearField( - com.google.protobuf.Descriptors.FieldDescriptor field) { - return (Builder) super.clearField(field); - } - - public Builder clearOneof( - com.google.protobuf.Descriptors.OneofDescriptor oneof) { - return (Builder) super.clearOneof(oneof); - } - - public Builder setRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - int index, Object value) { - return (Builder) super.setRepeatedField(field, index, value); - } - - public Builder addRepeatedField( - com.google.protobuf.Descriptors.FieldDescriptor field, - Object value) { - return (Builder) super.addRepeatedField(field, value); - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof AddressBookProtos.Person.PhoneNumber) { - return mergeFrom((AddressBookProtos.Person.PhoneNumber) other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(AddressBookProtos.Person.PhoneNumber other) { - if (other == AddressBookProtos.Person.PhoneNumber.getDefaultInstance()) - return this; - if (other.hasNumber()) { - bitField0_ |= 0x00000001; - number_ = other.number_; - onChanged(); - } - if (other.hasType()) { - setType(other.getType()); - } - this.mergeUnknownFields(other.unknownFields); - onChanged(); - return this; - } - - public final boolean isInitialized() { - if (!hasNumber()) { - return false; - } - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - AddressBookProtos.Person.PhoneNumber parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (AddressBookProtos.Person.PhoneNumber) e.getUnfinishedMessage(); - throw e.unwrapIOException(); - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - - private int bitField0_; - - private java.lang.Object number_ = ""; - - /** - * required string number = 1; - */ - public boolean hasNumber() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - - /** - * required string number = 1; - */ - public java.lang.String getNumber() { - java.lang.Object ref = number_; - if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; - java.lang.String s = bs.toStringUtf8(); - if (bs.isValidUtf8()) { - number_ = s; - } - return s; - } else { - return (java.lang.String) ref; - } - } - - /** - * required string number = 1; - */ - public com.google.protobuf.ByteString - getNumberBytes() { - java.lang.Object ref = number_; - if (ref instanceof String) { - com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); - number_ = b; - return b; - } else { - return (com.google.protobuf.ByteString) ref; - } - } - - /** - * required string number = 1; - */ - public Builder setNumber( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - number_ = value; - onChanged(); - return this; - } - - /** - * required string number = 1; - */ - public Builder clearNumber() { - bitField0_ = (bitField0_ & ~0x00000001); - number_ = getDefaultInstance().getNumber(); - onChanged(); - return this; - } - - /** - * required string number = 1; - */ - public Builder setNumberBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000001; - number_ = value; - onChanged(); - return this; - } - - private int type_ = 1; - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public boolean hasType() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public AddressBookProtos.Person.PhoneType getType() { - AddressBookProtos.Person.PhoneType result = AddressBookProtos.Person.PhoneType.valueOf(type_); - return result == null ? AddressBookProtos.Person.PhoneType.HOME : result; - } - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public Builder setType(AddressBookProtos.Person.PhoneType value) { - if (value == null) { - throw new NullPointerException(); - } - bitField0_ |= 0x00000002; - type_ = value.getNumber(); - onChanged(); - return this; - } - - /** - * optional .protobuf.Person.PhoneType type = 2 [default = HOME]; - */ - public Builder clearType() { - bitField0_ = (bitField0_ & ~0x00000002); - type_ = 1; - onChanged(); - return this; - } - - public final Builder setUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.setUnknownFields(unknownFields); - } - - public final Builder mergeUnknownFields( - final com.google.protobuf.UnknownFieldSet unknownFields) { - return super.mergeUnknownFields(unknownFields); - } - - - // @@protoc_insertion_point(builder_scope:protobuf.Person.PhoneNumber) - } - - // @@protoc_insertion_point(class_scope:protobuf.Person.PhoneNumber) - private static final AddressBookProtos.Person.PhoneNumber DEFAULT_INSTANCE; - - static { - DEFAULT_INSTANCE = new AddressBookProtos.Person.PhoneNumber(); - } - - public static AddressBookProtos.Person.PhoneNumber getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - @java.lang.Deprecated - public static final com.google.protobuf.Parser - PARSER = new com.google.protobuf.AbstractParser() { - public PhoneNumber parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new PhoneNumber(input, extensionRegistry); - } - }; - - public static com.google.protobuf.Parser parser() { - return PARSER; - } - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - public AddressBookProtos.Person.PhoneNumber getDefaultInstanceForType() { - return DEFAULT_INSTANCE; - } - + com.baeldung.protobuf.AddressBookProtos.Person.class, com.baeldung.protobuf.AddressBookProtos.Person.Builder.class); } private int bitField0_; @@ -1107,44 +296,37 @@ public final class AddressBookProtos { } } - public static final int PHONES_FIELD_NUMBER = 4; - private java.util.List phones_; + public static final int NUMBERS_FIELD_NUMBER = 4; + private com.google.protobuf.LazyStringList numbers_; /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public java.util.List getPhonesList() { - return phones_; + public com.google.protobuf.ProtocolStringList + getNumbersList() { + return numbers_; } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public java.util.List - getPhonesOrBuilderList() { - return phones_; + public int getNumbersCount() { + return numbers_.size(); } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public int getPhonesCount() { - return phones_.size(); + public java.lang.String getNumbers(int index) { + return numbers_.get(index); } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public AddressBookProtos.Person.PhoneNumber getPhones(int index) { - return phones_.get(index); - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( - int index) { - return phones_.get(index); + public com.google.protobuf.ByteString + getNumbersBytes(int index) { + return numbers_.getByteString(index); } private byte memoizedIsInitialized = -1; @@ -1162,12 +344,6 @@ public final class AddressBookProtos { memoizedIsInitialized = 0; return false; } - for (int i = 0; i < getPhonesCount(); i++) { - if (!getPhones(i).isInitialized()) { - memoizedIsInitialized = 0; - return false; - } - } memoizedIsInitialized = 1; return true; } @@ -1183,8 +359,8 @@ public final class AddressBookProtos { if (((bitField0_ & 0x00000004) == 0x00000004)) { com.google.protobuf.GeneratedMessageV3.writeString(output, 3, email_); } - for (int i = 0; i < phones_.size(); i++) { - output.writeMessage(4, phones_.get(i)); + for (int i = 0; i < numbers_.size(); i++) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, numbers_.getRaw(i)); } unknownFields.writeTo(output); } @@ -1204,9 +380,13 @@ public final class AddressBookProtos { if (((bitField0_ & 0x00000004) == 0x00000004)) { size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, email_); } - for (int i = 0; i < phones_.size(); i++) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(4, phones_.get(i)); + { + int dataSize = 0; + for (int i = 0; i < numbers_.size(); i++) { + dataSize += computeStringSizeNoTag(numbers_.getRaw(i)); + } + size += dataSize; + size += 1 * getNumbersList().size(); } size += unknownFields.getSerializedSize(); memoizedSize = size; @@ -1220,10 +400,10 @@ public final class AddressBookProtos { if (obj == this) { return true; } - if (!(obj instanceof AddressBookProtos.Person)) { + if (!(obj instanceof com.baeldung.protobuf.AddressBookProtos.Person)) { return super.equals(obj); } - AddressBookProtos.Person other = (AddressBookProtos.Person) obj; + com.baeldung.protobuf.AddressBookProtos.Person other = (com.baeldung.protobuf.AddressBookProtos.Person) obj; boolean result = true; result = result && (hasName() == other.hasName()); @@ -1241,8 +421,8 @@ public final class AddressBookProtos { result = result && getEmail() .equals(other.getEmail()); } - result = result && getPhonesList() - .equals(other.getPhonesList()); + result = result && getNumbersList() + .equals(other.getNumbersList()); result = result && unknownFields.equals(other.unknownFields); return result; } @@ -1266,47 +446,47 @@ public final class AddressBookProtos { hash = (37 * hash) + EMAIL_FIELD_NUMBER; hash = (53 * hash) + getEmail().hashCode(); } - if (getPhonesCount() > 0) { - hash = (37 * hash) + PHONES_FIELD_NUMBER; - hash = (53 * hash) + getPhonesList().hashCode(); + if (getNumbersCount() > 0) { + hash = (37 * hash) + NUMBERS_FIELD_NUMBER; + hash = (53 * hash) + getNumbersList().hashCode(); } hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static AddressBookProtos.Person parseFrom(byte[] data) + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static AddressBookProtos.Person parseFrom(java.io.InputStream input) + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1314,13 +494,13 @@ public final class AddressBookProtos { .parseWithIOException(PARSER, input, extensionRegistry); } - public static AddressBookProtos.Person parseDelimitedFrom(java.io.InputStream input) + public static com.baeldung.protobuf.AddressBookProtos.Person parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseDelimitedWithIOException(PARSER, input); } - public static AddressBookProtos.Person parseDelimitedFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1328,14 +508,14 @@ public final class AddressBookProtos { .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } - public static AddressBookProtos.Person parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.Person parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -1351,7 +531,7 @@ public final class AddressBookProtos { return DEFAULT_INSTANCE.toBuilder(); } - public static Builder newBuilder(AddressBookProtos.Person prototype) { + public static Builder newBuilder(com.baeldung.protobuf.AddressBookProtos.Person prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @@ -1373,20 +553,20 @@ public final class AddressBookProtos { public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements // @@protoc_insertion_point(builder_implements:protobuf.Person) - AddressBookProtos.PersonOrBuilder { + com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return AddressBookProtos.internal_static_protobuf_Person_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_Person_descriptor; } protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_Person_fieldAccessorTable .ensureFieldAccessorsInitialized( - AddressBookProtos.Person.class, AddressBookProtos.Person.Builder.class); + com.baeldung.protobuf.AddressBookProtos.Person.class, com.baeldung.protobuf.AddressBookProtos.Person.Builder.class); } - // Construct using AddressBookProtos.Person.newBuilder() + // Construct using com.baeldung.protobuf.AddressBookProtos.Person.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -1400,7 +580,6 @@ public final class AddressBookProtos { private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessageV3 .alwaysUseFieldBuilders) { - getPhonesFieldBuilder(); } } @@ -1412,34 +591,30 @@ public final class AddressBookProtos { bitField0_ = (bitField0_ & ~0x00000002); email_ = ""; bitField0_ = (bitField0_ & ~0x00000004); - if (phonesBuilder_ == null) { - phones_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - } else { - phonesBuilder_.clear(); - } + numbers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); return this; } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return AddressBookProtos.internal_static_protobuf_Person_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_Person_descriptor; } - public AddressBookProtos.Person getDefaultInstanceForType() { - return AddressBookProtos.Person.getDefaultInstance(); + public com.baeldung.protobuf.AddressBookProtos.Person getDefaultInstanceForType() { + return com.baeldung.protobuf.AddressBookProtos.Person.getDefaultInstance(); } - public AddressBookProtos.Person build() { - AddressBookProtos.Person result = buildPartial(); + public com.baeldung.protobuf.AddressBookProtos.Person build() { + com.baeldung.protobuf.AddressBookProtos.Person result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - public AddressBookProtos.Person buildPartial() { - AddressBookProtos.Person result = new AddressBookProtos.Person(this); + public com.baeldung.protobuf.AddressBookProtos.Person buildPartial() { + com.baeldung.protobuf.AddressBookProtos.Person result = new com.baeldung.protobuf.AddressBookProtos.Person(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -1454,15 +629,11 @@ public final class AddressBookProtos { to_bitField0_ |= 0x00000004; } result.email_ = email_; - if (phonesBuilder_ == null) { - if (((bitField0_ & 0x00000008) == 0x00000008)) { - phones_ = java.util.Collections.unmodifiableList(phones_); - bitField0_ = (bitField0_ & ~0x00000008); - } - result.phones_ = phones_; - } else { - result.phones_ = phonesBuilder_.build(); + if (((bitField0_ & 0x00000008) == 0x00000008)) { + numbers_ = numbers_.getUnmodifiableView(); + bitField0_ = (bitField0_ & ~0x00000008); } + result.numbers_ = numbers_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -1501,16 +672,16 @@ public final class AddressBookProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof AddressBookProtos.Person) { - return mergeFrom((AddressBookProtos.Person) other); + if (other instanceof com.baeldung.protobuf.AddressBookProtos.Person) { + return mergeFrom((com.baeldung.protobuf.AddressBookProtos.Person) other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(AddressBookProtos.Person other) { - if (other == AddressBookProtos.Person.getDefaultInstance()) return this; + public Builder mergeFrom(com.baeldung.protobuf.AddressBookProtos.Person other) { + if (other == com.baeldung.protobuf.AddressBookProtos.Person.getDefaultInstance()) return this; if (other.hasName()) { bitField0_ |= 0x00000001; name_ = other.name_; @@ -1524,31 +695,15 @@ public final class AddressBookProtos { email_ = other.email_; onChanged(); } - if (phonesBuilder_ == null) { - if (!other.phones_.isEmpty()) { - if (phones_.isEmpty()) { - phones_ = other.phones_; - bitField0_ = (bitField0_ & ~0x00000008); - } else { - ensurePhonesIsMutable(); - phones_.addAll(other.phones_); - } - onChanged(); - } - } else { - if (!other.phones_.isEmpty()) { - if (phonesBuilder_.isEmpty()) { - phonesBuilder_.dispose(); - phonesBuilder_ = null; - phones_ = other.phones_; - bitField0_ = (bitField0_ & ~0x00000008); - phonesBuilder_ = - com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ? - getPhonesFieldBuilder() : null; - } else { - phonesBuilder_.addAllMessages(other.phones_); - } + if (!other.numbers_.isEmpty()) { + if (numbers_.isEmpty()) { + numbers_ = other.numbers_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureNumbersIsMutable(); + numbers_.addAll(other.numbers_); } + onChanged(); } this.mergeUnknownFields(other.unknownFields); onChanged(); @@ -1562,11 +717,6 @@ public final class AddressBookProtos { if (!hasId()) { return false; } - for (int i = 0; i < getPhonesCount(); i++) { - if (!getPhones(i).isInitialized()) { - return false; - } - } return true; } @@ -1574,11 +724,11 @@ public final class AddressBookProtos { com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - AddressBookProtos.Person parsedMessage = null; + com.baeldung.protobuf.AddressBookProtos.Person parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (AddressBookProtos.Person) e.getUnfinishedMessage(); + parsedMessage = (com.baeldung.protobuf.AddressBookProtos.Person) e.getUnfinishedMessage(); throw e.unwrapIOException(); } finally { if (parsedMessage != null) { @@ -1790,266 +940,109 @@ public final class AddressBookProtos { return this; } - private java.util.List phones_ = - java.util.Collections.emptyList(); + private com.google.protobuf.LazyStringList numbers_ = com.google.protobuf.LazyStringArrayList.EMPTY; - private void ensurePhonesIsMutable() { + private void ensureNumbersIsMutable() { if (!((bitField0_ & 0x00000008) == 0x00000008)) { - phones_ = new java.util.ArrayList(phones_); + numbers_ = new com.google.protobuf.LazyStringArrayList(numbers_); bitField0_ |= 0x00000008; } } - private com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder> phonesBuilder_; - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public java.util.List getPhonesList() { - if (phonesBuilder_ == null) { - return java.util.Collections.unmodifiableList(phones_); - } else { - return phonesBuilder_.getMessageList(); - } + public com.google.protobuf.ProtocolStringList + getNumbersList() { + return numbers_.getUnmodifiableView(); } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public int getPhonesCount() { - if (phonesBuilder_ == null) { - return phones_.size(); - } else { - return phonesBuilder_.getCount(); - } + public int getNumbersCount() { + return numbers_.size(); } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public AddressBookProtos.Person.PhoneNumber getPhones(int index) { - if (phonesBuilder_ == null) { - return phones_.get(index); - } else { - return phonesBuilder_.getMessage(index); - } + public java.lang.String getNumbers(int index) { + return numbers_.get(index); } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public Builder setPhones( - int index, AddressBookProtos.Person.PhoneNumber value) { - if (phonesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePhonesIsMutable(); - phones_.set(index, value); - onChanged(); - } else { - phonesBuilder_.setMessage(index, value); + public com.google.protobuf.ByteString + getNumbersBytes(int index) { + return numbers_.getByteString(index); + } + + /** + * repeated string numbers = 4; + */ + public Builder setNumbers( + int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); } + ensureNumbersIsMutable(); + numbers_.set(index, value); + onChanged(); return this; } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public Builder setPhones( - int index, AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { - if (phonesBuilder_ == null) { - ensurePhonesIsMutable(); - phones_.set(index, builderForValue.build()); - onChanged(); - } else { - phonesBuilder_.setMessage(index, builderForValue.build()); + public Builder addNumbers( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); } + ensureNumbersIsMutable(); + numbers_.add(value); + onChanged(); return this; } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public Builder addPhones(AddressBookProtos.Person.PhoneNumber value) { - if (phonesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePhonesIsMutable(); - phones_.add(value); - onChanged(); - } else { - phonesBuilder_.addMessage(value); - } + public Builder addAllNumbers( + java.lang.Iterable values) { + ensureNumbersIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, numbers_); + onChanged(); return this; } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public Builder addPhones( - int index, AddressBookProtos.Person.PhoneNumber value) { - if (phonesBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - ensurePhonesIsMutable(); - phones_.add(index, value); - onChanged(); - } else { - phonesBuilder_.addMessage(index, value); - } + public Builder clearNumbers() { + numbers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); return this; } /** - * repeated .protobuf.Person.PhoneNumber phones = 4; + * repeated string numbers = 4; */ - public Builder addPhones( - AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { - if (phonesBuilder_ == null) { - ensurePhonesIsMutable(); - phones_.add(builderForValue.build()); - onChanged(); - } else { - phonesBuilder_.addMessage(builderForValue.build()); + public Builder addNumbersBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); } + ensureNumbersIsMutable(); + numbers_.add(value); + onChanged(); return this; } - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public Builder addPhones( - int index, AddressBookProtos.Person.PhoneNumber.Builder builderForValue) { - if (phonesBuilder_ == null) { - ensurePhonesIsMutable(); - phones_.add(index, builderForValue.build()); - onChanged(); - } else { - phonesBuilder_.addMessage(index, builderForValue.build()); - } - return this; - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public Builder addAllPhones( - java.lang.Iterable values) { - if (phonesBuilder_ == null) { - ensurePhonesIsMutable(); - com.google.protobuf.AbstractMessageLite.Builder.addAll( - values, phones_); - onChanged(); - } else { - phonesBuilder_.addAllMessages(values); - } - return this; - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public Builder clearPhones() { - if (phonesBuilder_ == null) { - phones_ = java.util.Collections.emptyList(); - bitField0_ = (bitField0_ & ~0x00000008); - onChanged(); - } else { - phonesBuilder_.clear(); - } - return this; - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public Builder removePhones(int index) { - if (phonesBuilder_ == null) { - ensurePhonesIsMutable(); - phones_.remove(index); - onChanged(); - } else { - phonesBuilder_.remove(index); - } - return this; - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public AddressBookProtos.Person.PhoneNumber.Builder getPhonesBuilder( - int index) { - return getPhonesFieldBuilder().getBuilder(index); - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public AddressBookProtos.Person.PhoneNumberOrBuilder getPhonesOrBuilder( - int index) { - if (phonesBuilder_ == null) { - return phones_.get(index); - } else { - return phonesBuilder_.getMessageOrBuilder(index); - } - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public java.util.List - getPhonesOrBuilderList() { - if (phonesBuilder_ != null) { - return phonesBuilder_.getMessageOrBuilderList(); - } else { - return java.util.Collections.unmodifiableList(phones_); - } - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public AddressBookProtos.Person.PhoneNumber.Builder addPhonesBuilder() { - return getPhonesFieldBuilder().addBuilder( - AddressBookProtos.Person.PhoneNumber.getDefaultInstance()); - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public AddressBookProtos.Person.PhoneNumber.Builder addPhonesBuilder( - int index) { - return getPhonesFieldBuilder().addBuilder( - index, AddressBookProtos.Person.PhoneNumber.getDefaultInstance()); - } - - /** - * repeated .protobuf.Person.PhoneNumber phones = 4; - */ - public java.util.List - getPhonesBuilderList() { - return getPhonesFieldBuilder().getBuilderList(); - } - - private com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder> - getPhonesFieldBuilder() { - if (phonesBuilder_ == null) { - phonesBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person.PhoneNumber, AddressBookProtos.Person.PhoneNumber.Builder, AddressBookProtos.Person.PhoneNumberOrBuilder>( - phones_, - ((bitField0_ & 0x00000008) == 0x00000008), - getParentForChildren(), - isClean()); - phones_ = null; - } - return phonesBuilder_; - } - public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); @@ -2065,13 +1058,13 @@ public final class AddressBookProtos { } // @@protoc_insertion_point(class_scope:protobuf.Person) - private static final AddressBookProtos.Person DEFAULT_INSTANCE; + private static final com.baeldung.protobuf.AddressBookProtos.Person DEFAULT_INSTANCE; static { - DEFAULT_INSTANCE = new AddressBookProtos.Person(); + DEFAULT_INSTANCE = new com.baeldung.protobuf.AddressBookProtos.Person(); } - public static AddressBookProtos.Person getDefaultInstance() { + public static com.baeldung.protobuf.AddressBookProtos.Person getDefaultInstance() { return DEFAULT_INSTANCE; } @@ -2095,7 +1088,7 @@ public final class AddressBookProtos { return PARSER; } - public AddressBookProtos.Person getDefaultInstanceForType() { + public com.baeldung.protobuf.AddressBookProtos.Person getDefaultInstanceForType() { return DEFAULT_INSTANCE; } @@ -2108,13 +1101,13 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - java.util.List + java.util.List getPeopleList(); /** * repeated .protobuf.Person people = 1; */ - AddressBookProtos.Person getPeople(int index); + com.baeldung.protobuf.AddressBookProtos.Person getPeople(int index); /** * repeated .protobuf.Person people = 1; @@ -2124,13 +1117,13 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - java.util.List + java.util.List getPeopleOrBuilderList(); /** * repeated .protobuf.Person people = 1; */ - AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( int index); } @@ -2181,11 +1174,11 @@ public final class AddressBookProtos { } case 10: { if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { - people_ = new java.util.ArrayList(); + people_ = new java.util.ArrayList(); mutable_bitField0_ |= 0x00000001; } people_.add( - input.readMessage(AddressBookProtos.Person.PARSER, extensionRegistry)); + input.readMessage(com.baeldung.protobuf.AddressBookProtos.Person.PARSER, extensionRegistry)); break; } } @@ -2206,30 +1199,30 @@ public final class AddressBookProtos { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; } protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable .ensureFieldAccessorsInitialized( - AddressBookProtos.AddressBook.class, AddressBookProtos.AddressBook.Builder.class); + com.baeldung.protobuf.AddressBookProtos.AddressBook.class, com.baeldung.protobuf.AddressBookProtos.AddressBook.Builder.class); } public static final int PEOPLE_FIELD_NUMBER = 1; - private java.util.List people_; + private java.util.List people_; /** * repeated .protobuf.Person people = 1; */ - public java.util.List getPeopleList() { + public java.util.List getPeopleList() { return people_; } /** * repeated .protobuf.Person people = 1; */ - public java.util.List + public java.util.List getPeopleOrBuilderList() { return people_; } @@ -2244,14 +1237,14 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.Person getPeople(int index) { + public com.baeldung.protobuf.AddressBookProtos.Person getPeople(int index) { return people_.get(index); } /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + public com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( int index) { return people_.get(index); } @@ -2302,10 +1295,10 @@ public final class AddressBookProtos { if (obj == this) { return true; } - if (!(obj instanceof AddressBookProtos.AddressBook)) { + if (!(obj instanceof com.baeldung.protobuf.AddressBookProtos.AddressBook)) { return super.equals(obj); } - AddressBookProtos.AddressBook other = (AddressBookProtos.AddressBook) obj; + com.baeldung.protobuf.AddressBookProtos.AddressBook other = (com.baeldung.protobuf.AddressBookProtos.AddressBook) obj; boolean result = true; result = result && getPeopleList() @@ -2330,38 +1323,38 @@ public final class AddressBookProtos { return hash; } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static AddressBookProtos.AddressBook parseFrom(byte[] data) + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static AddressBookProtos.AddressBook parseFrom(java.io.InputStream input) + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -2369,13 +1362,13 @@ public final class AddressBookProtos { .parseWithIOException(PARSER, input, extensionRegistry); } - public static AddressBookProtos.AddressBook parseDelimitedFrom(java.io.InputStream input) + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseDelimitedWithIOException(PARSER, input); } - public static AddressBookProtos.AddressBook parseDelimitedFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -2383,14 +1376,14 @@ public final class AddressBookProtos { .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3 .parseWithIOException(PARSER, input); } - public static AddressBookProtos.AddressBook parseFrom( + public static com.baeldung.protobuf.AddressBookProtos.AddressBook parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -2406,7 +1399,7 @@ public final class AddressBookProtos { return DEFAULT_INSTANCE.toBuilder(); } - public static Builder newBuilder(AddressBookProtos.AddressBook prototype) { + public static Builder newBuilder(com.baeldung.protobuf.AddressBookProtos.AddressBook prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @@ -2428,20 +1421,20 @@ public final class AddressBookProtos { public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements // @@protoc_insertion_point(builder_implements:protobuf.AddressBook) - AddressBookProtos.AddressBookOrBuilder { + com.baeldung.protobuf.AddressBookProtos.AddressBookOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; } protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internalGetFieldAccessorTable() { - return AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_AddressBook_fieldAccessorTable .ensureFieldAccessorsInitialized( - AddressBookProtos.AddressBook.class, AddressBookProtos.AddressBook.Builder.class); + com.baeldung.protobuf.AddressBookProtos.AddressBook.class, com.baeldung.protobuf.AddressBookProtos.AddressBook.Builder.class); } - // Construct using AddressBookProtos.AddressBook.newBuilder() + // Construct using com.baeldung.protobuf.AddressBookProtos.AddressBook.newBuilder() private Builder() { maybeForceBuilderInitialization(); } @@ -2472,23 +1465,23 @@ public final class AddressBookProtos { public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; + return com.baeldung.protobuf.AddressBookProtos.internal_static_protobuf_AddressBook_descriptor; } - public AddressBookProtos.AddressBook getDefaultInstanceForType() { - return AddressBookProtos.AddressBook.getDefaultInstance(); + public com.baeldung.protobuf.AddressBookProtos.AddressBook getDefaultInstanceForType() { + return com.baeldung.protobuf.AddressBookProtos.AddressBook.getDefaultInstance(); } - public AddressBookProtos.AddressBook build() { - AddressBookProtos.AddressBook result = buildPartial(); + public com.baeldung.protobuf.AddressBookProtos.AddressBook build() { + com.baeldung.protobuf.AddressBookProtos.AddressBook result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - public AddressBookProtos.AddressBook buildPartial() { - AddressBookProtos.AddressBook result = new AddressBookProtos.AddressBook(this); + public com.baeldung.protobuf.AddressBookProtos.AddressBook buildPartial() { + com.baeldung.protobuf.AddressBookProtos.AddressBook result = new com.baeldung.protobuf.AddressBookProtos.AddressBook(this); int from_bitField0_ = bitField0_; if (peopleBuilder_ == null) { if (((bitField0_ & 0x00000001) == 0x00000001)) { @@ -2536,16 +1529,16 @@ public final class AddressBookProtos { } public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof AddressBookProtos.AddressBook) { - return mergeFrom((AddressBookProtos.AddressBook) other); + if (other instanceof com.baeldung.protobuf.AddressBookProtos.AddressBook) { + return mergeFrom((com.baeldung.protobuf.AddressBookProtos.AddressBook) other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(AddressBookProtos.AddressBook other) { - if (other == AddressBookProtos.AddressBook.getDefaultInstance()) return this; + public Builder mergeFrom(com.baeldung.protobuf.AddressBookProtos.AddressBook other) { + if (other == com.baeldung.protobuf.AddressBookProtos.AddressBook.getDefaultInstance()) return this; if (peopleBuilder_ == null) { if (!other.people_.isEmpty()) { if (people_.isEmpty()) { @@ -2590,11 +1583,11 @@ public final class AddressBookProtos { com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { - AddressBookProtos.AddressBook parsedMessage = null; + com.baeldung.protobuf.AddressBookProtos.AddressBook parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (AddressBookProtos.AddressBook) e.getUnfinishedMessage(); + parsedMessage = (com.baeldung.protobuf.AddressBookProtos.AddressBook) e.getUnfinishedMessage(); throw e.unwrapIOException(); } finally { if (parsedMessage != null) { @@ -2606,23 +1599,23 @@ public final class AddressBookProtos { private int bitField0_; - private java.util.List people_ = + private java.util.List people_ = java.util.Collections.emptyList(); private void ensurePeopleIsMutable() { if (!((bitField0_ & 0x00000001) == 0x00000001)) { - people_ = new java.util.ArrayList(people_); + people_ = new java.util.ArrayList(people_); bitField0_ |= 0x00000001; } } private com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder> peopleBuilder_; + com.baeldung.protobuf.AddressBookProtos.Person, com.baeldung.protobuf.AddressBookProtos.Person.Builder, com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder> peopleBuilder_; /** * repeated .protobuf.Person people = 1; */ - public java.util.List getPeopleList() { + public java.util.List getPeopleList() { if (peopleBuilder_ == null) { return java.util.Collections.unmodifiableList(people_); } else { @@ -2644,7 +1637,7 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.Person getPeople(int index) { + public com.baeldung.protobuf.AddressBookProtos.Person getPeople(int index) { if (peopleBuilder_ == null) { return people_.get(index); } else { @@ -2656,7 +1649,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder setPeople( - int index, AddressBookProtos.Person value) { + int index, com.baeldung.protobuf.AddressBookProtos.Person value) { if (peopleBuilder_ == null) { if (value == null) { throw new NullPointerException(); @@ -2674,7 +1667,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder setPeople( - int index, AddressBookProtos.Person.Builder builderForValue) { + int index, com.baeldung.protobuf.AddressBookProtos.Person.Builder builderForValue) { if (peopleBuilder_ == null) { ensurePeopleIsMutable(); people_.set(index, builderForValue.build()); @@ -2688,7 +1681,7 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public Builder addPeople(AddressBookProtos.Person value) { + public Builder addPeople(com.baeldung.protobuf.AddressBookProtos.Person value) { if (peopleBuilder_ == null) { if (value == null) { throw new NullPointerException(); @@ -2706,7 +1699,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder addPeople( - int index, AddressBookProtos.Person value) { + int index, com.baeldung.protobuf.AddressBookProtos.Person value) { if (peopleBuilder_ == null) { if (value == null) { throw new NullPointerException(); @@ -2724,7 +1717,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder addPeople( - AddressBookProtos.Person.Builder builderForValue) { + com.baeldung.protobuf.AddressBookProtos.Person.Builder builderForValue) { if (peopleBuilder_ == null) { ensurePeopleIsMutable(); people_.add(builderForValue.build()); @@ -2739,7 +1732,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder addPeople( - int index, AddressBookProtos.Person.Builder builderForValue) { + int index, com.baeldung.protobuf.AddressBookProtos.Person.Builder builderForValue) { if (peopleBuilder_ == null) { ensurePeopleIsMutable(); people_.add(index, builderForValue.build()); @@ -2754,7 +1747,7 @@ public final class AddressBookProtos { * repeated .protobuf.Person people = 1; */ public Builder addAllPeople( - java.lang.Iterable values) { + java.lang.Iterable values) { if (peopleBuilder_ == null) { ensurePeopleIsMutable(); com.google.protobuf.AbstractMessageLite.Builder.addAll( @@ -2797,7 +1790,7 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.Person.Builder getPeopleBuilder( + public com.baeldung.protobuf.AddressBookProtos.Person.Builder getPeopleBuilder( int index) { return getPeopleFieldBuilder().getBuilder(index); } @@ -2805,7 +1798,7 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( + public com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder getPeopleOrBuilder( int index) { if (peopleBuilder_ == null) { return people_.get(index); @@ -2817,7 +1810,7 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public java.util.List + public java.util.List getPeopleOrBuilderList() { if (peopleBuilder_ != null) { return peopleBuilder_.getMessageOrBuilderList(); @@ -2829,34 +1822,34 @@ public final class AddressBookProtos { /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.Person.Builder addPeopleBuilder() { + public com.baeldung.protobuf.AddressBookProtos.Person.Builder addPeopleBuilder() { return getPeopleFieldBuilder().addBuilder( - AddressBookProtos.Person.getDefaultInstance()); + com.baeldung.protobuf.AddressBookProtos.Person.getDefaultInstance()); } /** * repeated .protobuf.Person people = 1; */ - public AddressBookProtos.Person.Builder addPeopleBuilder( + public com.baeldung.protobuf.AddressBookProtos.Person.Builder addPeopleBuilder( int index) { return getPeopleFieldBuilder().addBuilder( - index, AddressBookProtos.Person.getDefaultInstance()); + index, com.baeldung.protobuf.AddressBookProtos.Person.getDefaultInstance()); } /** * repeated .protobuf.Person people = 1; */ - public java.util.List + public java.util.List getPeopleBuilderList() { return getPeopleFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder> + com.baeldung.protobuf.AddressBookProtos.Person, com.baeldung.protobuf.AddressBookProtos.Person.Builder, com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder> getPeopleFieldBuilder() { if (peopleBuilder_ == null) { peopleBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3< - AddressBookProtos.Person, AddressBookProtos.Person.Builder, AddressBookProtos.PersonOrBuilder>( + com.baeldung.protobuf.AddressBookProtos.Person, com.baeldung.protobuf.AddressBookProtos.Person.Builder, com.baeldung.protobuf.AddressBookProtos.PersonOrBuilder>( people_, ((bitField0_ & 0x00000001) == 0x00000001), getParentForChildren(), @@ -2881,13 +1874,13 @@ public final class AddressBookProtos { } // @@protoc_insertion_point(class_scope:protobuf.AddressBook) - private static final AddressBookProtos.AddressBook DEFAULT_INSTANCE; + private static final com.baeldung.protobuf.AddressBookProtos.AddressBook DEFAULT_INSTANCE; static { - DEFAULT_INSTANCE = new AddressBookProtos.AddressBook(); + DEFAULT_INSTANCE = new com.baeldung.protobuf.AddressBookProtos.AddressBook(); } - public static AddressBookProtos.AddressBook getDefaultInstance() { + public static com.baeldung.protobuf.AddressBookProtos.AddressBook getDefaultInstance() { return DEFAULT_INSTANCE; } @@ -2911,7 +1904,7 @@ public final class AddressBookProtos { return PARSER; } - public AddressBookProtos.AddressBook getDefaultInstanceForType() { + public com.baeldung.protobuf.AddressBookProtos.AddressBook getDefaultInstanceForType() { return DEFAULT_INSTANCE; } @@ -2922,11 +1915,6 @@ public final class AddressBookProtos { private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_protobuf_Person_fieldAccessorTable; - private static final com.google.protobuf.Descriptors.Descriptor - internal_static_protobuf_Person_PhoneNumber_descriptor; - private static final - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable; private static final com.google.protobuf.Descriptors.Descriptor internal_static_protobuf_AddressBook_descriptor; private static final @@ -2943,15 +1931,11 @@ public final class AddressBookProtos { static { java.lang.String[] descriptorData = { - "\n\020routeguide.proto\022\010protobuf\"\333\001\n\006Person\022" + - "\014\n\004name\030\001 \002(\t\022\n\n\002id\030\002 \002(\005\022\r\n\005email\030\003 \001(\t" + - "\022,\n\006phones\030\004 \003(\0132\034.protobuf.Person.Phone" + - "Number\032M\n\013PhoneNumber\022\016\n\006number\030\001 \002(\t\022.\n" + - "\004type\030\002 \001(\0162\032.protobuf.Person.PhoneType:" + - "\004HOME\"+\n\tPhoneType\022\n\n\006MOBILE\020\000\022\010\n\004HOME\020\001" + - "\022\010\n\004WORK\020\002\"/\n\013AddressBook\022 \n\006people\030\001 \003(" + - "\0132\020.protobuf.PersonB*\n\025com.baeldung.prot" + - "obufB\021AddressBookProtos" + "\n\020routeguide.proto\022\010protobuf\"B\n\006Person\022\014" + + "\n\004name\030\001 \002(\t\022\n\n\002id\030\002 \002(\005\022\r\n\005email\030\003 \001(\t\022" + + "\017\n\007numbers\030\004 \003(\t\"/\n\013AddressBook\022 \n\006peopl" + + "e\030\001 \003(\0132\020.protobuf.PersonB*\n\025com.baeldun" + + "g.protobufB\021AddressBookProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -2970,13 +1954,7 @@ public final class AddressBookProtos { internal_static_protobuf_Person_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_protobuf_Person_descriptor, - new java.lang.String[]{"Name", "Id", "Email", "Phones",}); - internal_static_protobuf_Person_PhoneNumber_descriptor = - internal_static_protobuf_Person_descriptor.getNestedTypes().get(0); - internal_static_protobuf_Person_PhoneNumber_fieldAccessorTable = new - com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_protobuf_Person_PhoneNumber_descriptor, - new java.lang.String[]{"Number", "Type",}); + new java.lang.String[]{"Name", "Id", "Email", "Numbers",}); internal_static_protobuf_AddressBook_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_protobuf_AddressBook_fieldAccessorTable = new @@ -2985,5 +1963,5 @@ public final class AddressBookProtos { new java.lang.String[]{"People",}); } - // @@protoc_insertion_point(outer_class_scope) +// @@protoc_insertion_point(outer_class_scope) } \ No newline at end of file diff --git a/protobuffer/src/main/resources/addressbook.proto b/protobuffer/src/main/resources/addressbook.proto index 1c0946b7f7..fe3f9c4174 100644 --- a/protobuffer/src/main/resources/addressbook.proto +++ b/protobuffer/src/main/resources/addressbook.proto @@ -8,18 +8,7 @@ message Person { required int32 id = 2; optional string email = 3; - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - required string number = 1; - optional PhoneType type = 2 [default = HOME]; - } - - repeated PhoneNumber phones = 4; + repeated string numbers = 4; } message AddressBook { diff --git a/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java b/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java index 74447eb4a4..f0d64092f0 100644 --- a/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java +++ b/protobuffer/src/test/java/com/baeldung/protobuf/ProtobufTest.java @@ -28,24 +28,18 @@ public class ProtobufTest { int id = new Random().nextInt(); String name = "Michael Program"; String number = "01234567890"; - AddressBookProtos.Person.PhoneType type = AddressBookProtos.Person.PhoneType.HOME; AddressBookProtos.Person person = AddressBookProtos.Person.newBuilder() .setId(id) .setName(name) .setEmail(email) - .addPhones( - AddressBookProtos.Person.PhoneNumber.newBuilder() - .setNumber(number) - .setType(type)) + .addNumbers(number) .build(); //then assertEquals(person.getEmail(), email); assertEquals(person.getId(), id); assertEquals(person.getName(), name); - assertEquals(person.getPhones(0).getNumber(), number); - assertEquals(person.getPhones(0).getType(), type); - assertEquals(person.getPhonesList().size(), 1); + assertEquals(person.getNumbers(0), number); } @@ -56,16 +50,12 @@ public class ProtobufTest { int id = new Random().nextInt(); String name = "Michael Program"; String number = "01234567890"; - AddressBookProtos.Person.PhoneType type = AddressBookProtos.Person.PhoneType.HOME; AddressBookProtos.Person person = AddressBookProtos.Person.newBuilder() .setId(id) .setName(name) .setEmail(email) - .addPhones( - AddressBookProtos.Person.PhoneNumber.newBuilder() - .setNumber(number) - .setType(type)) + .addNumbers(number) .build(); //when @@ -82,9 +72,8 @@ public class ProtobufTest { assertEquals(deserialized.getPeople(0).getEmail(), email); assertEquals(deserialized.getPeople(0).getId(), id); assertEquals(deserialized.getPeople(0).getName(), name); - assertEquals(deserialized.getPeople(0).getPhones(0).getNumber(), number); - assertEquals(deserialized.getPeople(0).getPhones(0).getType(), type); - assertEquals(deserialized.getPeople(0).getPhonesList().size(), 1); + assertEquals(deserialized.getPeople(0).getNumbers(0), number); + } } diff --git a/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.0 b/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.0 new file mode 100644 index 0000000000..78d5d3fcf3 --- /dev/null +++ b/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.0 @@ -0,0 +1,24 @@ +https://publicobject.com/helloworld.txt +GET +0 +HTTP/1.1 200 OK +10 +Server: nginx/1.10.0 (Ubuntu) +Date: Thu, 09 Mar 2017 10:17:25 GMT +Content-Type: text/plain +Content-Length: 1759 +Last-Modified: Tue, 27 May 2014 02:35:47 GMT +Connection: keep-alive +ETag: "5383fa03-6df" +Accept-Ranges: bytes +OkHttp-Sent-Millis: 1489054646765 +OkHttp-Received-Millis: 1489054646966 + +TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +4 +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 +0 +TLSv1.2 diff --git a/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.1 b/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.1 new file mode 100644 index 0000000000..83db2312f0 --- /dev/null +++ b/spring-rest/src/test/resources/cache/2d9345a30d2cc31bb3091d70a8ef6c18.1 @@ -0,0 +1,39 @@ + + \\ // + \\ .ooo. // + .@@@@@@@@@. + :@@@@@@@@@@@@@: + :@@. '@@@@@' .@@: + @@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@ + + :@@ :@@@@@@@@@@@@@@@@@. @@: + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@ '@@@@@@@@@@@@@@@@@, @@@ + @@@@@@@@@@@@@@@@@ + '@@@@@@@@@@@@@@@' + @@@@ @@@@ + @@@@ @@@@ + @@@@ @@@@ + '@@' '@@' + + :@@@. + .@@@@@@@: +@@ `@@ @@` @@ @@ + .@@@@'@@@@: +@@ `@@ @@` @@ @@ + @@@ @@@ +@@ `@@ @@` @@ @@ + .@@ @@: +@@ @@@ `@@ @@` @@@@@@ @@@@@@ @@;@@@@@ + @@@ @@@ +@@ @@@ `@@ @@` @@@@@@ @@@@@@ @@@@@@@@@ + @@@ @@@ +@@ @@@ `@@@@@@@@@@` @@ @@ @@@ :@@ + @@@ @@@ +@@@@@ `@@@@@@@@@@` @@ @@ @@# @@+ + @@@ @@@ +@@@@@+ `@@ @@` @@ @@ @@: @@# + @@: .@@` +@@@+@@ `@@ @@` @@ @@ @@# @@+ + @@@. .@@@ +@@ @@@ `@@ @@` @@ @@ @@@ ,@@ + @@@@@@@@@ +@@ @@@ `@@ @@` @@@@ @@@@ @@@@#@@@@ + @@@@@@@ +@@ #@@ `@@ @@` @@@@: @@@@: @@'@@@@@ + @@: + @@: + @@: diff --git a/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.0 b/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.0 new file mode 100644 index 0000000000..82c93f0a86 --- /dev/null +++ b/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.0 @@ -0,0 +1,13 @@ +http://publicobject.com/helloworld.txt +GET +0 +HTTP/1.1 301 Moved Permanently +8 +Server: nginx/1.10.0 (Ubuntu) +Date: Thu, 09 Mar 2017 10:17:25 GMT +Content-Type: text/html +Content-Length: 194 +Connection: keep-alive +Location: https://publicobject.com/helloworld.txt +OkHttp-Sent-Millis: 1489054646977 +OkHttp-Received-Millis: 1489054647185 diff --git a/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.1 b/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.1 new file mode 100644 index 0000000000..acf72eabe3 --- /dev/null +++ b/spring-rest/src/test/resources/cache/4b217e04ba52215f3a6b64d28f6729c6.1 @@ -0,0 +1,7 @@ + +301 Moved Permanently + +

301 Moved Permanently

+
nginx/1.10.0 (Ubuntu)
+ + diff --git a/spring-rest/src/test/resources/cache/journal b/spring-rest/src/test/resources/cache/journal new file mode 100644 index 0000000000..44b709c179 --- /dev/null +++ b/spring-rest/src/test/resources/cache/journal @@ -0,0 +1,12 @@ +libcore.io.DiskLruCache +1 +201105 +2 + +DIRTY 4b217e04ba52215f3a6b64d28f6729c6 +CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194 +DIRTY 2d9345a30d2cc31bb3091d70a8ef6c18 +CLEAN 2d9345a30d2cc31bb3091d70a8ef6c18 7618 1759 +READ 4b217e04ba52215f3a6b64d28f6729c6 +DIRTY 4b217e04ba52215f3a6b64d28f6729c6 +CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194 From 9b48f77c8d1f48aef50f6936b24d0b94f607b550 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 25 Mar 2017 11:47:14 +0100 Subject: [PATCH 183/291] ContactNumberValidator refactor (#1491) * ContactNumberValidator refactor * Refactor controllers --- .../customvalidator/ContactNumberValidator.java | 5 +---- .../com/baeldung/web/controller/UserController.java | 7 ++++--- .../web/controller/ValidatedPhoneController.java | 13 ++++++------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java index 713b7429cf..dea6b9099b 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java +++ b/spring-mvc-java/src/main/java/com/baeldung/customvalidator/ContactNumberValidator.java @@ -11,10 +11,7 @@ public class ContactNumberValidator implements ConstraintValidator 8) && (contactField.length() < 14); + return contactField != null && contactField.matches("[0-9]+") && (contactField.length() > 8) && (contactField.length() < 14); } } diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/UserController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/UserController.java index fda159f204..e72ec06830 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/UserController.java +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/UserController.java @@ -3,15 +3,16 @@ package com.baeldung.web.controller; import com.baeldung.model.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/") public class UserController { - @RequestMapping(value = "/", method = RequestMethod.GET) + @GetMapping("/") public String showForm(final Model model) { final User user = new User(); user.setFirstname("John"); @@ -21,7 +22,7 @@ public class UserController { return "index"; } - @RequestMapping(value = "/processForm", method = RequestMethod.POST) + @PostMapping("/processForm") public String processForm(@ModelAttribute(value = "user") final User user, final Model model) { // Insert User into DB model.addAttribute("name", user.getFirstname() + " " + user.getLastname()); diff --git a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java index 54b0e19e60..8c6cfcd3be 100644 --- a/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java +++ b/spring-mvc-java/src/main/java/com/baeldung/web/controller/ValidatedPhoneController.java @@ -1,27 +1,26 @@ package com.baeldung.web.controller; -import javax.validation.Valid; - +import com.baeldung.model.ValidatedPhone; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import com.baeldung.model.ValidatedPhone; +import javax.validation.Valid; @Controller @EnableWebMvc public class ValidatedPhoneController { - @RequestMapping(value = "/validatePhone", method = RequestMethod.GET) + @GetMapping("/validatePhone") public String loadFormPage(Model m) { m.addAttribute("validatedPhone", new ValidatedPhone()); return "phoneHome"; } - @RequestMapping(value = "/addValidatePhone", method = RequestMethod.POST) + @PostMapping("/addValidatePhone") public String submitForm(@Valid ValidatedPhone validatedPhone, BindingResult result, Model m) { if (result.hasErrors()) { return "phoneHome"; From e62f8fa3d8ce4e8671c59065401cccc58384f016 Mon Sep 17 00:00:00 2001 From: buddhini81 Date: Sun, 26 Mar 2017 00:20:46 +0530 Subject: [PATCH 184/291] Add javaEE annotation sample project (#1481) * Delete AccountServlet.java * Delete BankAppServletContextListener.java * Delete LogInFilter.java * Delete UploadCustomerDocumentsServlet.java * Delete index.jsp * Delete login.jsp * Delete upload.jsp * Delete web.xml * Create javaeeannotations * Delete javaeeannotations * commit javaEE annotations project --- .../JavaEEAnnotationsSample/pom.xml | 57 ++++++++++++++++++ .../javaeeannotations}/AccountServlet.java | 13 ++--- .../BankAppServletContextListener.java | 34 +++++------ .../DepositRequestListener.java | 20 +++++++ .../javaeeannotations}/LogInFilter.java | 8 +-- .../UploadCustomerDocumentsServlet.java | 58 +++++++++---------- .../src/main}/webapp/index.jsp | 30 +++++----- .../src/main}/webapp/login.jsp | 22 +++---- .../src/main}/webapp/upload.jsp | 30 +++++----- .../src/main/webapp}/web.xml | 20 +++---- 10 files changed, 183 insertions(+), 109 deletions(-) create mode 100644 jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml rename jee7/src/main/java/com/baeldung/javaeeannotations/{ => JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations}/AccountServlet.java (85%) rename jee7/src/main/java/com/baeldung/javaeeannotations/{ => JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations}/BankAppServletContextListener.java (96%) create mode 100644 jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java rename jee7/src/main/java/com/baeldung/javaeeannotations/{ => JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations}/LogInFilter.java (96%) rename jee7/src/main/java/com/baeldung/javaeeannotations/{ => JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations}/UploadCustomerDocumentsServlet.java (96%) rename jee7/src/main/{ => java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main}/webapp/index.jsp (79%) rename jee7/src/main/{ => java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main}/webapp/login.jsp (97%) rename jee7/src/main/{ => java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main}/webapp/upload.jsp (97%) rename jee7/src/main/{webapp/WEB-INF => java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp}/web.xml (97%) diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml new file mode 100644 index 0000000000..b4bb243559 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml @@ -0,0 +1,57 @@ + + 4.0.0 + com.baeldung.javaeeannotations + JavaEEAnnotationsSample + 0.0.1-SNAPSHOT + war + JavaEEAnnotationsSample + JavaEEAnnotationsSample + + + + + javax.annotation + javax.annotation-api + 1.3 + + + + javax.servlet + javax.servlet-api + 3.1.0 + + + + javax.servlet.jsp + jsp-api + 2.1 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + src/main/webapp + SpringFieldConstructorInjection + false + + + + + JavaEEAnnotationsSample + + \ No newline at end of file diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java similarity index 85% rename from jee7/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java index e3f1667595..e24eb307bb 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java @@ -5,9 +5,6 @@ import java.io.PrintWriter; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.annotation.HttpConstraint; -import javax.servlet.annotation.HttpMethodConstraint; -import javax.servlet.annotation.ServletSecurity; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; @@ -19,20 +16,20 @@ import javax.servlet.http.HttpServletResponse; urlPatterns = {"/account", "/bankAccount" }, initParams = { @WebInitParam(name = "type", value = "savings") } ) -@ServletSecurity( +/*@ServletSecurity( value = @HttpConstraint(rolesAllowed = {"admin"}), httpMethodConstraints = {@HttpMethodConstraint(value = "POST", rolesAllowed = {"admin"})} - ) + )*/ public class AccountServlet extends javax.servlet.http.HttpServlet { String accountType = null; - @Override public void init(ServletConfig config) throws ServletException { accountType = config.getInitParameter("type"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + PrintWriter writer = response.getWriter(); writer.println("Hello, I am an AccountServlet!"); writer.flush(); @@ -49,8 +46,8 @@ public class AccountServlet extends javax.servlet.http.HttpServlet { PrintWriter writer = response.getWriter(); writer.println(" Balance of " + accountType + " account is: " + - accountBalance + "
This account bares an interest rate of " + interestRate + - " % "); + accountBalance + "
This account bares an interest rate of " + interestRate + + " % "); writer.flush(); } diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java similarity index 96% rename from jee7/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java index 6b43dd8a84..ee1b624cd1 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java @@ -1,17 +1,17 @@ -package com.baeldung.javaeeannotations; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.annotation.WebListener; - -@WebListener -public class BankAppServletContextListener implements ServletContextListener { - - public void contextInitialized(ServletContextEvent sce) { - sce.getServletContext().setAttribute("ATTR_DEFAULT_LANGUAGE", "english"); - } - - public void contextDestroyed(ServletContextEvent sce) { - System.out.println("CONTEXT DESTROYED"); - } -} +package com.baeldung.javaeeannotations; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class BankAppServletContextListener implements ServletContextListener { + + public void contextInitialized(ServletContextEvent sce) { + sce.getServletContext().setAttribute("ATTR_DEFAULT_LANGUAGE", "english"); + } + + public void contextDestroyed(ServletContextEvent sce) { + System.out.println("CONTEXT DESTROYED"); + } +} diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java new file mode 100644 index 0000000000..f361c84b97 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java @@ -0,0 +1,20 @@ +package com.baeldung.javaeeannotations; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; + +@WebListener +public class DepositRequestListener implements ServletRequestListener { + + public void requestDestroyed(ServletRequestEvent event) { + + } + + public void requestInitialized(ServletRequestEvent evet) { + HttpServletRequest req = (HttpServletRequest)evet.getServletRequest(); + req.setAttribute("interest", new Double(10)); + } + +} diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java similarity index 96% rename from jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java index 4e4aef2672..5ee420f6a2 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java @@ -11,13 +11,13 @@ import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -@WebFilter( +/*@WebFilter( urlPatterns = "/bankAccount/*", filterName = "LogInFilter", description = "Filter all account transaction URLs" - ) + )*/ public class LogInFilter implements javax.servlet.Filter { - @Override + public void init(FilterConfig filterConfig) throws ServletException { } @@ -29,8 +29,8 @@ public class LogInFilter implements javax.servlet.Filter { chain.doFilter(request, response); } - @Override public void destroy() { + } } diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java similarity index 96% rename from jee7/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java index 8a6c709b81..3a139ad7cc 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java @@ -1,29 +1,29 @@ -package com.baeldung.javaeeannotations; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.annotation.MultipartConfig; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Part; - -@WebServlet(urlPatterns = { "/uploadCustDocs" }) -@MultipartConfig( - fileSizeThreshold = 1024 * 1024 * 20, - maxFileSize = 1024 * 1024 * 20, - maxRequestSize = 1024 * 1024 * 25, - location = "D:/custDocs" - ) -public class UploadCustomerDocumentsServlet extends HttpServlet { - - protected void doPost( - HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - for (Part part : request.getParts()) { - part.write("myFile"); - } - } - -} +package com.baeldung.javaeeannotations; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.MultipartConfig; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Part; + +@WebServlet(urlPatterns = { "/uploadCustDocs" }) +@MultipartConfig( + fileSizeThreshold = 1024 * 1024 * 20, + maxFileSize = 1024 * 1024 * 20, + maxRequestSize = 1024 * 1024 * 25, + location = "D:/custDocs" + ) +public class UploadCustomerDocumentsServlet extends HttpServlet { + + protected void doPost( + HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + for (Part part : request.getParts()) { + part.write("myFile"); + } + } + +} diff --git a/jee7/src/main/webapp/index.jsp b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp similarity index 79% rename from jee7/src/main/webapp/index.jsp rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp index 0c389ef5b1..c49dec859e 100644 --- a/jee7/src/main/webapp/index.jsp +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp @@ -1,16 +1,16 @@ -<%@ page language="java" contentType="text/html; charset=ISO-8859-1" - pageEncoding="ISO-8859-1"%> - - - - -My Account - - -
- Width: -    - -
- +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +My Account + + +
+ Amount: +    + +
+ \ No newline at end of file diff --git a/jee7/src/main/webapp/login.jsp b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp similarity index 97% rename from jee7/src/main/webapp/login.jsp rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp index 885df0c3d9..6892cb0420 100644 --- a/jee7/src/main/webapp/login.jsp +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp @@ -1,12 +1,12 @@ -<%@ page language="java" contentType="text/html; charset=ISO-8859-1" - pageEncoding="ISO-8859-1"%> - - - - -Login - - -Login Here... - +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +Login + + +Login Here... + \ No newline at end of file diff --git a/jee7/src/main/webapp/upload.jsp b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp similarity index 97% rename from jee7/src/main/webapp/upload.jsp rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp index 020483b99f..3601322ef0 100644 --- a/jee7/src/main/webapp/upload.jsp +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp @@ -1,16 +1,16 @@ -<%@ page language="java" contentType="text/html; charset=ISO-8859-1" - pageEncoding="ISO-8859-1"%> - - - - -Insert title here - - -
- -
- -
- +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +Insert title here + + +
+ +
+ +
+ \ No newline at end of file diff --git a/jee7/src/main/webapp/WEB-INF/web.xml b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/web.xml similarity index 97% rename from jee7/src/main/webapp/WEB-INF/web.xml rename to jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/web.xml index 0a3d84d2d4..f01eb341e4 100644 --- a/jee7/src/main/webapp/WEB-INF/web.xml +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/web.xml @@ -1,11 +1,11 @@ - - - - BASIC - default - - + + + + BASIC + default + + \ No newline at end of file From de29cd56327f0b532d587053f1c997e07d6c88c6 Mon Sep 17 00:00:00 2001 From: baljeet20 Date: Sun, 26 Mar 2017 01:53:04 +0530 Subject: [PATCH 185/291] BAEL-750 Added Java configuration (#1494) * BAEL-750 A guide to gemfire with spring data * BAEL-750 A guide to gemfire with spring data * BAEL-750 A guide to gemfire with spring data --- pom.xml | 3 +- spring-data-gemfire/pom.xml | 97 ++++++++++++++++++ .../gemfire/function/FunctionExecution.java | 16 +++ .../data/gemfire/function/FunctionImpl.java | 18 ++++ .../function/GemfireConfiguration.java | 65 ++++++++++++ .../spring/data/gemfire/model/Employee.java | 41 ++++++++ .../repository/EmployeeRepository.java | 17 ++++ .../main/resources/application-context.xml | 20 ++++ .../repository/EmployeeRepositoryTest.java | 98 +++++++++++++++++++ 9 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 spring-data-gemfire/pom.xml create mode 100644 spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionExecution.java create mode 100644 spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionImpl.java create mode 100644 spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/GemfireConfiguration.java create mode 100644 spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/model/Employee.java create mode 100644 spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepository.java create mode 100644 spring-data-gemfire/src/main/resources/application-context.xml create mode 100644 spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java diff --git a/pom.xml b/pom.xml index 5c85e94546..e0295e5c72 100644 --- a/pom.xml +++ b/pom.xml @@ -211,7 +211,8 @@ rabbitmq vertx - + spring-data-gemfire + diff --git a/spring-data-gemfire/pom.xml b/spring-data-gemfire/pom.xml new file mode 100644 index 0000000000..f387b04651 --- /dev/null +++ b/spring-data-gemfire/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + + com.baeldung + spring-data-gemfire + 1.0.0-SNAPSHOT + jar + + 2.19.1 + 1.7.4.RELEASE + 7.0.1 + 1.0 + 4.12 + 1.3 + 4.3.0.RELEASE + 4.3.0.RELEASE + + + + + org.springframework.data + spring-data-gemfire + ${spring-data-gemfire-version} + + + + com.gemstone.gemfire + gemfire + ${gemfire-version} + + + + com.google.collections + google-collections + ${google-collections-version} + + + + junit + junit + ${junit-version} + test + + + org.hamcrest + hamcrest-core + + + + + org.hamcrest + hamcrest-library + ${hamcrest-library-version} + test + + + org.springframework + spring-context + ${spring-context-version} + + + org.springframework + spring-test + ${spring-test-version} + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + + + + + spring-snapshots + Spring Snapshots + http://repo.spring.io/libs-snapshot + + true + + + + gemstone + http://dist.gemstone.com.s3.amazonaws.com/maven/release/ + + + + \ No newline at end of file diff --git a/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionExecution.java b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionExecution.java new file mode 100644 index 0000000000..a3ddf32414 --- /dev/null +++ b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionExecution.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.data.gemfire.function; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.gemfire.function.annotation.FunctionId; +import org.springframework.data.gemfire.function.annotation.OnRegion; +import org.springframework.data.gemfire.function.annotation.RegionData; + +import java.util.Map; +import java.util.Set; + +@OnRegion(region="employee") +public interface FunctionExecution { + @FunctionId("greeting") + public void execute(String message); + +} diff --git a/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionImpl.java b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionImpl.java new file mode 100644 index 0000000000..9fc6a2155d --- /dev/null +++ b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/FunctionImpl.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.data.gemfire.function; + +import org.springframework.data.gemfire.function.annotation.GemfireFunction; +import org.springframework.stereotype.Component; + +@Component +public class FunctionImpl { + + @GemfireFunction + public void greeting(String message){ + System.out.println("Message "+message); + } + + @GemfireFunction + public String sayHello(String message){ + return "Hello "+message; + } +} diff --git a/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/GemfireConfiguration.java b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/GemfireConfiguration.java new file mode 100644 index 0000000000..0049f82ddc --- /dev/null +++ b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/function/GemfireConfiguration.java @@ -0,0 +1,65 @@ +package com.baeldung.spring.data.gemfire.function; + +import com.baeldung.spring.data.gemfire.model.Employee; +import com.baeldung.spring.data.gemfire.repository.EmployeeRepository; +import com.gemstone.gemfire.cache.DataPolicy; +import com.gemstone.gemfire.cache.GemFireCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions; +import org.springframework.data.gemfire.function.config.EnableGemfireFunctions; +import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories; +import java.util.Properties; + +@Configuration +@ComponentScan +@EnableGemfireRepositories(basePackages = "com.baeldung.spring.data.gemfire.repository") +@EnableGemfireFunctions +@EnableGemfireFunctionExecutions(basePackages = "com.baeldung.spring.data.gemfire.function") +public class GemfireConfiguration { + + @Autowired + EmployeeRepository employeeRepository; + + @Autowired + FunctionExecution functionExecution; + + + @Bean + Properties gemfireProperties() { + Properties gemfireProperties = new Properties(); + gemfireProperties.setProperty("name", "SpringDataGemFireApplication"); + gemfireProperties.setProperty("mcast-port", "0"); + gemfireProperties.setProperty("log-level", "config"); + return gemfireProperties; + } + + @Bean + @Autowired + CacheFactoryBean gemfireCache() { + CacheFactoryBean gemfireCache = new CacheFactoryBean(); + gemfireCache.setClose(true); + gemfireCache.setProperties(gemfireProperties()); + return gemfireCache; + } + + + @Bean(name="employee") + @Autowired + LocalRegionFactoryBean getEmployee(final GemFireCache cache) { + LocalRegionFactoryBean employeeRegion = new LocalRegionFactoryBean(); + employeeRegion.setCache(cache); + employeeRegion.setClose(false); + employeeRegion.setName("employee"); + employeeRegion.setPersistent(false); + employeeRegion.setDataPolicy(DataPolicy.PRELOADED); + return employeeRegion; + } + + +} + diff --git a/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/model/Employee.java b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/model/Employee.java new file mode 100644 index 0000000000..9c29b28dca --- /dev/null +++ b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/model/Employee.java @@ -0,0 +1,41 @@ +package com.baeldung.spring.data.gemfire.model; + +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.gemfire.mapping.Region; + + +@Region("employee") +public class Employee { + + @Id + public String name; + public double salary; + + @PersistenceConstructor + public Employee(String name, double salary) { + this.name = name; + this.salary = salary; + } + + @Override + public String toString() { + return name + " is " + salary + " years old."; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getSalary() { + return salary; + } + + public void setSalary(int salary) { + this.salary = salary; + } +} \ No newline at end of file diff --git a/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepository.java b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepository.java new file mode 100644 index 0000000000..30799a2b99 --- /dev/null +++ b/spring-data-gemfire/src/main/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepository.java @@ -0,0 +1,17 @@ +package com.baeldung.spring.data.gemfire.repository; + +import com.baeldung.spring.data.gemfire.model.Employee; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EmployeeRepository extends CrudRepository { + + Employee findByName(String name); + + Iterable findBySalaryGreaterThan(double salary); + + Iterable findBySalaryLessThan(double salary); + + Iterable findBySalaryGreaterThanAndSalaryLessThan(double salary1, double salary2); +} diff --git a/spring-data-gemfire/src/main/resources/application-context.xml b/spring-data-gemfire/src/main/resources/application-context.xml new file mode 100644 index 0000000000..e618719b30 --- /dev/null +++ b/spring-data-gemfire/src/main/resources/application-context.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java b/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java new file mode 100644 index 0000000000..8714ad2d81 --- /dev/null +++ b/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java @@ -0,0 +1,98 @@ +package com.baeldung.spring.data.gemfire.repository; + +import com.baeldung.spring.data.gemfire.function.FunctionExecution; +import com.baeldung.spring.data.gemfire.function.GemfireConfiguration; +import com.baeldung.spring.data.gemfire.model.Employee; +import com.google.common.collect.Lists; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import java.util.List; + +import static junit.framework.Assert.assertEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes=GemfireConfiguration.class, loader=AnnotationConfigContextLoader.class) +public class EmployeeRepositoryTest { + + @Autowired + EmployeeRepository employeeRepository; + + @Autowired + FunctionExecution execution; + + @Test + public void whenEmployeeIsSaved_ThenAbleToRead(){ + Employee employee=new Employee("John Davidson",4550.00); + employeeRepository.save(employee); + + List employees= Lists.newArrayList(employeeRepository.findAll()); + + assertEquals(1, employees.size()); + } + + @Test + public void whenSalaryGreaterThan_ThenEmployeeFound(){ + + Employee employee=new Employee("John Davidson",4550.00); + Employee employee1=new Employee("Adam Davidson",3500.00); + Employee employee2=new Employee("Chris Davidson",5600.00); + + employeeRepository.save(employee); + employeeRepository.save(employee1); + employeeRepository.save(employee2); + + List employees= Lists.newArrayList(employeeRepository.findBySalaryGreaterThan(4000.00)); + + assertEquals(2,employees.size()); + + } + + @Test + public void whenSalaryLessThan_ThenEmployeeFound(){ + + Employee employee=new Employee("John Davidson",4550.00); + Employee employee1=new Employee("Adam Davidson",3500.00); + Employee employee2=new Employee("Chris Davidson",5600.00); + + employeeRepository.save(employee); + employeeRepository.save(employee1); + employeeRepository.save(employee2); + + List employees= Lists.newArrayList(employeeRepository.findBySalaryLessThan(4000)); + + assertEquals(1,employees.size()); + + } + @Test + public void whenSalaryBetween_ThenEmployeeFound(){ + + Employee employee=new Employee("John Davidson",4550.00); + Employee employee1=new Employee("Adam Davidson",3500.00); + Employee employee2=new Employee("Chris Davidson",5600.00); + + employeeRepository.save(employee); + employeeRepository.save(employee1); + employeeRepository.save(employee2); + + List employees= Lists.newArrayList(employeeRepository.findBySalaryGreaterThanAndSalaryLessThan(3500,5000)); + + assertEquals(1,employees.size()); + + } + + @Test + public void whenFunctionExecutedFromClient_ThenFunctionExecutedOnServer(){ + execution.execute("Hello World"); + } + + @After + public void cleanup(){ + employeeRepository.deleteAll(); + } +} From 052c149b0edb156eba9244d708d5b3a958d15e4f Mon Sep 17 00:00:00 2001 From: lor6 Date: Sat, 25 Mar 2017 23:12:17 +0200 Subject: [PATCH 186/291] in memory test (#1476) * in memory test * update dependencies * rename db * remove create db * update version --- spring-jpa/pom.xml | 8 +-- .../org/baeldung/config/StudentJpaConfig.java | 68 +++++++++++++++++++ .../persistence/dao/StudentRepository.java | 8 +++ .../baeldung/persistence/model/Student.java | 38 +++++++++++ .../resources/persistence-student.properties | 11 +++ .../repository/InMemoryDBTest.java | 38 +++++++++++ .../resources/persistence-student.properties | 9 +++ 7 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 spring-jpa/src/main/java/org/baeldung/config/StudentJpaConfig.java create mode 100644 spring-jpa/src/main/java/org/baeldung/persistence/dao/StudentRepository.java create mode 100644 spring-jpa/src/main/java/org/baeldung/persistence/model/Student.java create mode 100644 spring-jpa/src/main/resources/persistence-student.properties create mode 100644 spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBTest.java create mode 100644 spring-jpa/src/test/resources/persistence-student.properties diff --git a/spring-jpa/pom.xml b/spring-jpa/pom.xml index 2229d64abe..3ca373acea 100644 --- a/spring-jpa/pom.xml +++ b/spring-jpa/pom.xml @@ -196,14 +196,14 @@ - 4.3.4.RELEASE + 4.3.7.RELEASE 3.21.0-GA - 5.2.5.Final + 5.2.9.Final 5.1.40 - 1.10.5.RELEASE - 1.4.193 + 1.11.1.RELEASE + 1.4.194 1.2 diff --git a/spring-jpa/src/main/java/org/baeldung/config/StudentJpaConfig.java b/spring-jpa/src/main/java/org/baeldung/config/StudentJpaConfig.java new file mode 100644 index 0000000000..a40f180a62 --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/config/StudentJpaConfig.java @@ -0,0 +1,68 @@ +package org.baeldung.config; + +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao") +@PropertySource("persistence-student.properties") +@EnableTransactionManagement +public class StudentJpaConfig { + + @Autowired + private Environment env; + + @Bean + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName")); + dataSource.setUrl(env.getProperty("jdbc.url")); + dataSource.setUsername(env.getProperty("jdbc.user")); + dataSource.setPassword(env.getProperty("jdbc.pass")); + + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" }); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaProperties(additionalProperties()); + return em; + } + + @Bean + JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory); + return transactionManager; + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache")); + hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache")); + + return hibernateProperties; + } +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/dao/StudentRepository.java b/spring-jpa/src/main/java/org/baeldung/persistence/dao/StudentRepository.java new file mode 100644 index 0000000000..af484b442c --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/dao/StudentRepository.java @@ -0,0 +1,8 @@ +package org.baeldung.persistence.dao; + +import org.springframework.data.jpa.repository.JpaRepository; + +import org.baeldung.persistence.model.Student; + +public interface StudentRepository extends JpaRepository { +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/model/Student.java b/spring-jpa/src/main/java/org/baeldung/persistence/model/Student.java new file mode 100644 index 0000000000..437eeac5bb --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/model/Student.java @@ -0,0 +1,38 @@ +package org.baeldung.persistence.model; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Student { + + @Id + private long id; + private String name; + + public Student() { + } + + public Student(long id, String name) { + super(); + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/spring-jpa/src/main/resources/persistence-student.properties b/spring-jpa/src/main/resources/persistence-student.properties new file mode 100644 index 0000000000..4e80b836d2 --- /dev/null +++ b/spring-jpa/src/main/resources/persistence-student.properties @@ -0,0 +1,11 @@ +jdbc.driverClassName=com.mysql.jdbc.Driver +jdbc.url=jdbc:mysql://localhost:3306/myDb +jdbc.user=tutorialuser +jdbc.pass=tutorialpass + +hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop + +hibernate.cache.use_second_level_cache=false +hibernate.cache.use_query_cache=false \ No newline at end of file diff --git a/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBTest.java b/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBTest.java new file mode 100644 index 0000000000..2c40c5b117 --- /dev/null +++ b/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBTest.java @@ -0,0 +1,38 @@ +package org.baeldung.persistence.repository; + +import javax.annotation.Resource; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.transaction.annotation.Transactional; + +import org.baeldung.config.StudentJpaConfig; +import org.baeldung.persistence.model.Student; +import org.baeldung.persistence.dao.StudentRepository; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { StudentJpaConfig.class }, loader = AnnotationConfigContextLoader.class) +@Transactional +public class InMemoryDBTest { + + @Resource + private StudentRepository studentRepository; + + private static final long ID = 1; + private static final String NAME="john"; + + @Test + public void givenStudent_whenSave_thenGetOk(){ + Student student = new Student(ID, NAME); + studentRepository.save(student); + + Student student2 = studentRepository.findOne(ID); + assertEquals("name incorrect", NAME, student2.getName()); + } + +} diff --git a/spring-jpa/src/test/resources/persistence-student.properties b/spring-jpa/src/test/resources/persistence-student.properties new file mode 100644 index 0000000000..21dcd5b4a0 --- /dev/null +++ b/spring-jpa/src/test/resources/persistence-student.properties @@ -0,0 +1,9 @@ +jdbc.driverClassName=org.h2.Driver +jdbc.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop + +hibernate.cache.use_second_level_cache=false +hibernate.cache.use_query_cache=false \ No newline at end of file From 52eb7c2bc42081b589b9a566f594fe3817acfaa5 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Sun, 26 Mar 2017 15:56:20 +0200 Subject: [PATCH 187/291] Bael 738 (#1504) * BAEL-724 code for put/patch article * BAEL-724 fix typo * BAEL-728 more generic patch approach * BAEL-738 change url of PUT method * fix route confict --- .../repository/HeavyResourceRepository.java | 8 ++++++++ .../web/controller/HeavyResourceController.java | 14 +++++++------- .../controller/HeavyResourceControllerTest.java | 6 +++--- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java index 6de9e75450..5556d85f65 100644 --- a/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java +++ b/spring-rest/src/main/java/org/baeldung/repository/HeavyResourceRepository.java @@ -2,6 +2,7 @@ package org.baeldung.repository; import org.baeldung.web.dto.HeavyResource; import org.baeldung.web.dto.HeavyResourceAddressOnly; +import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate; import java.util.Map; @@ -17,4 +18,11 @@ public class HeavyResourceRepository { public void save(Map updates, String id) { } + + public void save(HeavyResource heavyResource, String id) { + + } + public void save(HeavyResourceAddressOnly partialUpdate, String id) { + + } } diff --git a/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java index f2c4ffaa51..55616a6446 100644 --- a/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java +++ b/spring-rest/src/main/java/org/baeldung/web/controller/HeavyResourceController.java @@ -15,19 +15,19 @@ public class HeavyResourceController { private HeavyResourceRepository heavyResourceRepository = new HeavyResourceRepository(); - @RequestMapping(value = "/heavy", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity saveResource(@RequestBody HeavyResource heavyResource) { - heavyResourceRepository.save(heavyResource); + @RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity saveResource(@RequestBody HeavyResource heavyResource, @PathVariable("id") String id) { + heavyResourceRepository.save(heavyResource, id); return ResponseEntity.ok("resource saved"); } - @RequestMapping(value = "/heavy", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity partialUpdateName(@RequestBody HeavyResourceAddressOnly partialUpdate) { - heavyResourceRepository.save(partialUpdate); + @RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity partialUpdateName(@RequestBody HeavyResourceAddressOnly partialUpdate, @PathVariable("id") String id) { + heavyResourceRepository.save(partialUpdate, id); return ResponseEntity.ok("resource address updated"); } - @RequestMapping(value = "/heavy/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) + @RequestMapping(value = "/heavyresource2/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity partialUpdateGeneric(@RequestBody Map updates, @PathVariable("id") String id) { heavyResourceRepository.save(updates, id); diff --git a/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java index e283c5f5f6..a1f9e71bec 100644 --- a/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java +++ b/spring-rest/src/test/java/org/baeldung/web/controller/HeavyResourceControllerTest.java @@ -42,7 +42,7 @@ public class HeavyResourceControllerTest { @Test public void givenHeavyResource_whenSendPutRequest_thenCreateResource() throws Exception { - mockMvc.perform(put("/heavy") + mockMvc.perform(put("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString(new HeavyResource(1, "Tom", "Jackson", 12, "heaven street"))) ).andExpect(status().isOk()); @@ -50,7 +50,7 @@ public class HeavyResourceControllerTest { @Test public void givenNewAddressOfResource_whenExecutePatchRequest_thenUpdateResourcePartially() throws Exception { - mockMvc.perform(patch("/heavy") + mockMvc.perform(patch("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString(new HeavyResourceAddressOnly(1, "5th avenue"))) ).andExpect(status().isOk()); @@ -61,7 +61,7 @@ public class HeavyResourceControllerTest { HashMap updates = new HashMap<>(); updates.put("address", "5th avenue"); - mockMvc.perform(patch("/heavy/1") + mockMvc.perform(patch("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString(updates)) ).andExpect(status().isOk()); From d3e57d38a620f76a4d288fa9ea0e95efe15fc09a Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Mon, 27 Mar 2017 00:23:28 +0800 Subject: [PATCH 188/291] #BAEL-636 (#1468) * jira #BAEL-636 * remove redundant dependency spring-boot-starter-reactive --- spring-5/pom.xml | 11 ++ .../java/com/baeldung/functional/Actor.java | 23 +++ .../com/baeldung/functional/FormHandler.java | 50 ++++++ .../functional/FunctionalWebApplication.java | 80 +++++++++ .../functional/IndexRewriteFilter.java | 29 ++++ spring-5/src/main/resources/files/hello.txt | 1 + ...nctionalWebApplicationIntegrationTest.java | 154 ++++++++++++++++++ .../src/test/resources/baeldung-weekly.png | Bin 0 -> 22275 bytes 8 files changed, 348 insertions(+) create mode 100644 spring-5/src/main/java/com/baeldung/functional/Actor.java create mode 100644 spring-5/src/main/java/com/baeldung/functional/FormHandler.java create mode 100644 spring-5/src/main/java/com/baeldung/functional/FunctionalWebApplication.java create mode 100644 spring-5/src/main/java/com/baeldung/functional/IndexRewriteFilter.java create mode 100644 spring-5/src/main/resources/files/hello.txt create mode 100644 spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java create mode 100644 spring-5/src/test/resources/baeldung-weekly.png diff --git a/spring-5/pom.xml b/spring-5/pom.xml index eca36cc1d1..59bead4b73 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -35,6 +35,17 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-webflux + + + + + io.projectreactor + reactor-core + 3.0.6.BUILD-SNAPSHOT + diff --git a/spring-5/src/main/java/com/baeldung/functional/Actor.java b/spring-5/src/main/java/com/baeldung/functional/Actor.java new file mode 100644 index 0000000000..23c88b89e1 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/Actor.java @@ -0,0 +1,23 @@ +package com.baeldung.functional; + +class Actor { + private String firstname; + private String lastname; + + public Actor() { + } + + public Actor(String firstname, String lastname) { + this.firstname = firstname; + this.lastname = lastname; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + +} diff --git a/spring-5/src/main/java/com/baeldung/functional/FormHandler.java b/spring-5/src/main/java/com/baeldung/functional/FormHandler.java new file mode 100644 index 0000000000..c44db76f56 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/FormHandler.java @@ -0,0 +1,50 @@ +package com.baeldung.functional; + +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import java.util.concurrent.atomic.AtomicLong; + +import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers; +import static org.springframework.web.reactive.function.BodyExtractors.toFormData; +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +public class FormHandler { + + Mono handleLogin(ServerRequest request) { + return request + .body(toFormData()) + .map(MultiValueMap::toSingleValueMap) + .map(formData -> { + System.out.println("form data: " + formData.toString()); + if ("baeldung".equals(formData.get("user")) && "you_know_what_to_do".equals(formData.get("token"))) { + return ok() + .body(Mono.just("welcome back!"), String.class) + .block(); + } + return ServerResponse + .badRequest() + .build() + .block(); + }); + } + + Mono handleUpload(ServerRequest request) { + return request + .body(toDataBuffers()) + .collectList() + .map(dataBuffers -> { + AtomicLong atomicLong = new AtomicLong(0); + dataBuffers.forEach(d -> atomicLong.addAndGet(d + .asByteBuffer() + .array().length)); + System.out.println("data length:" + atomicLong.get()); + return ok() + .body(fromObject(atomicLong.toString())) + .block(); + }); + } +} diff --git a/spring-5/src/main/java/com/baeldung/functional/FunctionalWebApplication.java b/spring-5/src/main/java/com/baeldung/functional/FunctionalWebApplication.java new file mode 100644 index 0000000000..573813b166 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/FunctionalWebApplication.java @@ -0,0 +1,80 @@ +package com.baeldung.functional; + +import org.apache.catalina.Context; +import org.apache.catalina.startup.Tomcat; +import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; +import org.springframework.boot.web.server.WebServer; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.http.server.reactive.ServletHttpHandlerAdapter; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; +import reactor.core.publisher.Flux; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.RequestPredicates.*; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +public class FunctionalWebApplication { + + private static final Actor BRAD_PITT = new Actor("Brad", "Pitt"); + private static final Actor TOM_HANKS = new Actor("Tom", "Hanks"); + private static final List actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS)); + + private RouterFunction routingFunction() { + FormHandler formHandler = new FormHandler(); + + RouterFunction restfulRouter = route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest + .bodyToMono(Actor.class) + .doOnNext(actors::add) + .then(ok().build())); + + return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))) + .andRoute(POST("/login"), formHandler::handleLogin) + .andRoute(POST("/upload"), formHandler::handleUpload) + .and(RouterFunctions.resources("/files/**", new ClassPathResource("files/"))) + .andNest(path("/actor"), restfulRouter) + .filter((request, next) -> { + System.out.println("Before handler invocation: " + request.path()); + return next.handle(request); + }); + } + + WebServer start() throws Exception { + WebHandler webHandler = toHttpHandler(routingFunction()); + HttpHandler httpHandler = WebHttpHandlerBuilder + .webHandler(webHandler) + .prependFilter(new IndexRewriteFilter()) + .build(); + + Tomcat tomcat = new Tomcat(); + tomcat.setHostname("localhost"); + tomcat.setPort(9090); + Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir")); + ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler); + Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet); + rootContext.addServletMappingDecoded("/", "httpHandlerServlet"); + + TomcatWebServer server = new TomcatWebServer(tomcat); + server.start(); + return server; + + } + + public static void main(String[] args) { + try { + new FunctionalWebApplication().start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/spring-5/src/main/java/com/baeldung/functional/IndexRewriteFilter.java b/spring-5/src/main/java/com/baeldung/functional/IndexRewriteFilter.java new file mode 100644 index 0000000000..3e19f81943 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/IndexRewriteFilter.java @@ -0,0 +1,29 @@ +package com.baeldung.functional; + +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +class IndexRewriteFilter implements WebFilter { + + @Override + public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { + ServerHttpRequest request = serverWebExchange.getRequest(); + if (request + .getURI() + .getPath() + .equals("/")) { + return webFilterChain.filter(serverWebExchange + .mutate() + .request(builder -> builder + .method(request.getMethod()) + .contextPath(request.getContextPath()) + .path("/test")) + .build()); + } + return webFilterChain.filter(serverWebExchange); + } + +} diff --git a/spring-5/src/main/resources/files/hello.txt b/spring-5/src/main/resources/files/hello.txt new file mode 100644 index 0000000000..b6fc4c620b --- /dev/null +++ b/spring-5/src/main/resources/files/hello.txt @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java b/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java new file mode 100644 index 0000000000..bf28ed1e7d --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java @@ -0,0 +1,154 @@ +package com.baeldung.functional; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.boot.web.server.WebServer; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.BodyInserters; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.BodyInserters.fromResource; + +public class FunctionalWebApplicationIntegrationTest { + + private static WebTestClient client; + private static WebServer server; + + @BeforeClass + public static void setup() throws Exception { + server = new FunctionalWebApplication().start(); + client = WebTestClient + .bindToServer() + .baseUrl("http://localhost:" + server.getPort()) + .build(); + } + + @AfterClass + public static void destroy() { + server.stop(); + } + + @Test + public void givenRouter_whenGetTest_thenGotHelloWorld() throws Exception { + client + .get() + .uri("/test") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .value() + .isEqualTo("helloworld"); + } + + @Test + public void givenIndexFilter_whenRequestRoot_thenRewrittenToTest() throws Exception { + client + .get() + .uri("/") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .value() + .isEqualTo("helloworld"); + } + + @Test + public void givenLoginForm_whenPostValidToken_thenSuccess() throws Exception { + MultiValueMap formData = new LinkedMultiValueMap<>(1); + formData.add("user", "baeldung"); + formData.add("token", "you_know_what_to_do"); + + client + .post() + .uri("/login") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .exchange(BodyInserters.fromFormData(formData)) + .expectStatus() + .isOk() + .expectBody(String.class) + .value() + .isEqualTo("welcome back!"); + } + + @Test + public void givenLoginForm_whenRequestWithInvalidToken_thenFail() throws Exception { + MultiValueMap formData = new LinkedMultiValueMap<>(2); + formData.add("user", "baeldung"); + formData.add("token", "try_again"); + + client + .post() + .uri("/login") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .exchange(BodyInserters.fromFormData(formData)) + .expectStatus() + .isBadRequest(); + } + + @Test + public void givenUploadForm_whenRequestWithMultipartData_thenSuccess() throws Exception { + Resource resource = new ClassPathResource("/baeldung-weekly.png"); + client + .post() + .uri("/upload") + .contentType(MediaType.MULTIPART_FORM_DATA) + .exchange(fromResource(resource)) + .expectStatus() + .isOk() + .expectBody(String.class) + .value() + .isEqualTo(String.valueOf(resource.contentLength())); + } + + @Test + public void givenActors_whenAddActor_thenAdded() throws Exception { + client + .get() + .uri("/actor") + .exchange() + .expectStatus() + .isOk() + .expectBody(Actor.class) + .list() + .hasSize(2); + + client + .post() + .uri("/actor") + .exchange(fromObject(new Actor("Clint", "Eastwood"))) + .expectStatus() + .isOk(); + + client + .get() + .uri("/actor") + .exchange() + .expectStatus() + .isOk() + .expectBody(Actor.class) + .list() + .hasSize(3); + } + + @Test + public void givenResources_whenAccess_thenGot() throws Exception { + client + .get() + .uri("/files/hello.txt") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .value() + .isEqualTo("hello"); + } + +} diff --git a/spring-5/src/test/resources/baeldung-weekly.png b/spring-5/src/test/resources/baeldung-weekly.png new file mode 100644 index 0000000000000000000000000000000000000000..5a27d61dae718016a947083e01411ed1bc14f90e GIT binary patch literal 22275 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 Date: Sun, 26 Mar 2017 19:38:09 +0200 Subject: [PATCH 189/291] Update pom.xml (#1507) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0295e5c72..0939ea91b8 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ javaxval jaxb jee7 - jhipster + jjwt jooq jpa-storedprocedure From 6322aa350f1c1a35d751463bd2bb57dbc03bf65e Mon Sep 17 00:00:00 2001 From: lor6 Date: Sun, 26 Mar 2017 21:19:07 +0300 Subject: [PATCH 190/291] Bael 737 v2 (#1509) * in memory test * update dependencies * rename db * remove create db * update version * update properties file --- spring-jpa/src/test/resources/persistence-student.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-jpa/src/test/resources/persistence-student.properties b/spring-jpa/src/test/resources/persistence-student.properties index 21dcd5b4a0..3b6b580630 100644 --- a/spring-jpa/src/test/resources/persistence-student.properties +++ b/spring-jpa/src/test/resources/persistence-student.properties @@ -3,7 +3,7 @@ jdbc.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.show_sql=true -hibernate.hbm2ddl.auto=create-drop +hibernate.hbm2ddl.auto=create hibernate.cache.use_second_level_cache=false hibernate.cache.use_query_cache=false \ No newline at end of file From e6836c01c7b6fb0ab058e93f9ef46aa6540a9c6d Mon Sep 17 00:00:00 2001 From: Mohamed Sanaulla Date: Sun, 26 Mar 2017 23:57:36 +0300 Subject: [PATCH 191/291] sample for BAEL-747 Check if a number is prime in Java (#1508) --- .../primechecker/BigIntegerPrimeChecker.java | 13 ++++++++++ .../primechecker/BruteForcePrimeChecker.java | 13 ++++++++++ .../primechecker/OptimisedPrimeChecker.java | 15 ++++++++++++ .../baeldung/primechecker/PrimeChecker.java | 6 +++++ .../primechecker/PrimesPrimeChecker.java | 12 ++++++++++ .../BigIntegerPrimeCheckerTest.java | 23 ++++++++++++++++++ .../BruteForcePrimeCheckerTest.java | 24 +++++++++++++++++++ .../OptimisedPrimeCheckerTest.java | 23 ++++++++++++++++++ .../primechecker/PrimesPrimeCheckerTest.java | 22 +++++++++++++++++ 9 files changed, 151 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/primechecker/BigIntegerPrimeChecker.java create mode 100644 core-java/src/main/java/com/baeldung/primechecker/BruteForcePrimeChecker.java create mode 100644 core-java/src/main/java/com/baeldung/primechecker/OptimisedPrimeChecker.java create mode 100644 core-java/src/main/java/com/baeldung/primechecker/PrimeChecker.java create mode 100644 core-java/src/main/java/com/baeldung/primechecker/PrimesPrimeChecker.java create mode 100644 core-java/src/test/java/com/baeldung/primechecker/BigIntegerPrimeCheckerTest.java create mode 100644 core-java/src/test/java/com/baeldung/primechecker/BruteForcePrimeCheckerTest.java create mode 100644 core-java/src/test/java/com/baeldung/primechecker/OptimisedPrimeCheckerTest.java create mode 100644 core-java/src/test/java/com/baeldung/primechecker/PrimesPrimeCheckerTest.java diff --git a/core-java/src/main/java/com/baeldung/primechecker/BigIntegerPrimeChecker.java b/core-java/src/main/java/com/baeldung/primechecker/BigIntegerPrimeChecker.java new file mode 100644 index 0000000000..1ac4fed63f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/primechecker/BigIntegerPrimeChecker.java @@ -0,0 +1,13 @@ +package com.baeldung.primechecker; + +import java.math.BigInteger; + +public class BigIntegerPrimeChecker implements PrimeChecker{ + + @Override + public boolean isPrime(int number) { + BigInteger bigInt = BigInteger.valueOf(number); + return bigInt.isProbablePrime(100); + } + +} diff --git a/core-java/src/main/java/com/baeldung/primechecker/BruteForcePrimeChecker.java b/core-java/src/main/java/com/baeldung/primechecker/BruteForcePrimeChecker.java new file mode 100644 index 0000000000..7a94479b8f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/primechecker/BruteForcePrimeChecker.java @@ -0,0 +1,13 @@ +package com.baeldung.primechecker; + +import java.util.stream.IntStream; + +public class BruteForcePrimeChecker implements PrimeChecker{ + + @Override + public boolean isPrime(int number) { + return IntStream.range(2, number).filter(n -> (number % n == 0)).count() == 0; + } + + +} diff --git a/core-java/src/main/java/com/baeldung/primechecker/OptimisedPrimeChecker.java b/core-java/src/main/java/com/baeldung/primechecker/OptimisedPrimeChecker.java new file mode 100644 index 0000000000..40669f4181 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/primechecker/OptimisedPrimeChecker.java @@ -0,0 +1,15 @@ +package com.baeldung.primechecker; + +import java.util.stream.IntStream; + +public class OptimisedPrimeChecker implements PrimeChecker{ + + @Override + public boolean isPrime(int number) { + return IntStream.range(2, (int)Math.sqrt(number) + 1) + .filter(n -> (number % n == 0)) + .count() == 0; + } + + +} diff --git a/core-java/src/main/java/com/baeldung/primechecker/PrimeChecker.java b/core-java/src/main/java/com/baeldung/primechecker/PrimeChecker.java new file mode 100644 index 0000000000..22260268bc --- /dev/null +++ b/core-java/src/main/java/com/baeldung/primechecker/PrimeChecker.java @@ -0,0 +1,6 @@ +package com.baeldung.primechecker; + +public interface PrimeChecker { + + public boolean isPrime( int number ); +} diff --git a/core-java/src/main/java/com/baeldung/primechecker/PrimesPrimeChecker.java b/core-java/src/main/java/com/baeldung/primechecker/PrimesPrimeChecker.java new file mode 100644 index 0000000000..0c6a636612 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/primechecker/PrimesPrimeChecker.java @@ -0,0 +1,12 @@ +package com.baeldung.primechecker; + +import org.apache.commons.math3.primes.Primes; + +public class PrimesPrimeChecker implements PrimeChecker{ + + @Override + public boolean isPrime(int number) { + return Primes.isPrime(number); + } + +} diff --git a/core-java/src/test/java/com/baeldung/primechecker/BigIntegerPrimeCheckerTest.java b/core-java/src/test/java/com/baeldung/primechecker/BigIntegerPrimeCheckerTest.java new file mode 100644 index 0000000000..6a5228cc50 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/primechecker/BigIntegerPrimeCheckerTest.java @@ -0,0 +1,23 @@ +package com.baeldung.primechecker; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class BigIntegerPrimeCheckerTest { + + PrimeChecker primeChecker = new BigIntegerPrimeChecker(); + + @Test + public void givenPrimeNumber_whenCheckIsPrime_thenTrue(){ + assertTrue(primeChecker.isPrime(13)); + assertTrue(primeChecker.isPrime(1009)); + } + + @Test + public void givenNonPrimeNumber_whenCheckIsPrime_thenFalse(){ + assertTrue(!primeChecker.isPrime(50)); + assertTrue(!primeChecker.isPrime(1001)); + } + +} diff --git a/core-java/src/test/java/com/baeldung/primechecker/BruteForcePrimeCheckerTest.java b/core-java/src/test/java/com/baeldung/primechecker/BruteForcePrimeCheckerTest.java new file mode 100644 index 0000000000..7139373f5e --- /dev/null +++ b/core-java/src/test/java/com/baeldung/primechecker/BruteForcePrimeCheckerTest.java @@ -0,0 +1,24 @@ +package com.baeldung.primechecker; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class BruteForcePrimeCheckerTest { + + BruteForcePrimeChecker primeChecker = new BruteForcePrimeChecker(); + + @Test + public void givenPrimeNumber_whenCheckIsPrime_thenTrue(){ + assertTrue(primeChecker.isPrime(13)); + assertTrue(primeChecker.isPrime(1009)); + } + + @Test + public void givenNonPrimeNumber_whenCheckIsPrime_thenFalse(){ + assertTrue(!primeChecker.isPrime(50)); + assertTrue(!primeChecker.isPrime(1001)); + } + + + +} diff --git a/core-java/src/test/java/com/baeldung/primechecker/OptimisedPrimeCheckerTest.java b/core-java/src/test/java/com/baeldung/primechecker/OptimisedPrimeCheckerTest.java new file mode 100644 index 0000000000..bb4c06a53a --- /dev/null +++ b/core-java/src/test/java/com/baeldung/primechecker/OptimisedPrimeCheckerTest.java @@ -0,0 +1,23 @@ +package com.baeldung.primechecker; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class OptimisedPrimeCheckerTest { + + PrimeChecker primeChecker = new OptimisedPrimeChecker(); + + @Test + public void givenPrimeNumber_whenCheckIsPrime_thenTrue(){ + assertTrue(primeChecker.isPrime(13)); + assertTrue(primeChecker.isPrime(1009)); + } + + @Test + public void givenNonPrimeNumber_whenCheckIsPrime_thenFalse(){ + assertTrue(!primeChecker.isPrime(50)); + assertTrue(!primeChecker.isPrime(1001)); + } + +} diff --git a/core-java/src/test/java/com/baeldung/primechecker/PrimesPrimeCheckerTest.java b/core-java/src/test/java/com/baeldung/primechecker/PrimesPrimeCheckerTest.java new file mode 100644 index 0000000000..f8b194e855 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/primechecker/PrimesPrimeCheckerTest.java @@ -0,0 +1,22 @@ +package com.baeldung.primechecker; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class PrimesPrimeCheckerTest { + PrimeChecker primeChecker = new PrimesPrimeChecker(); + + @Test + public void givenPrimeNumber_whenCheckIsPrime_thenTrue() { + assertTrue(primeChecker.isPrime(13)); + assertTrue(primeChecker.isPrime(1009)); + } + + @Test + public void givenNonPrimeNumber_whenCheckIsPrime_thenFalse() { + assertTrue(!primeChecker.isPrime(50)); + assertTrue(!primeChecker.isPrime(1001)); + } + +} From 427077ebfabc170f31e771c5486cc7a0cb25737b Mon Sep 17 00:00:00 2001 From: Nancy Bosecker Date: Mon, 27 Mar 2017 05:46:58 -0700 Subject: [PATCH 192/291] Jackson Map Serialize/Deserialize (#1511) * Solr w Apache SolrJ * Solr w Apache SolrJ * updated test names and moved add to @before method * create apache-solrj module, moved code from spring-data-solr * More examples for indexing,delete,and query for solrj * More examples for indexing,delete,and query for solrj * Jackson Map Serialize/Deserialize * Jackson Map Serialize/Deserialize --- .../com/baeldung/jackson/entities/MyPair.java | 80 +++++++++++++++++++ .../serialization/MyPairSerializer.java | 25 ++++++ .../JacksonMapDeserializeTest.java | 63 +++++++++++++++ .../JacksonMapSerializeTest.java | 71 ++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 jackson/src/main/java/com/baeldung/jackson/entities/MyPair.java create mode 100644 jackson/src/main/java/com/baeldung/jackson/serialization/MyPairSerializer.java create mode 100644 jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java create mode 100644 jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java diff --git a/jackson/src/main/java/com/baeldung/jackson/entities/MyPair.java b/jackson/src/main/java/com/baeldung/jackson/entities/MyPair.java new file mode 100644 index 0000000000..ebe41890fe --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/entities/MyPair.java @@ -0,0 +1,80 @@ +package com.baeldung.jackson.entities; + +import com.fasterxml.jackson.annotation.JsonValue; + +public class MyPair { + + private String first; + private String second; + + public MyPair(String first, String second) { + this.first = first; + this.second = second; + } + + public MyPair(String both) { + String[] pairs = both.split("and"); + this.first = pairs[0].trim(); + this.second = pairs[1].trim(); + } + + @Override + @JsonValue + public String toString() { + return first + " and " + second; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((first == null) ? 0 : first.hashCode()); + result = prime * result + ((second == null) ? 0 : second.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof MyPair)) { + return false; + } + MyPair other = (MyPair) obj; + if (first == null) { + if (other.first != null) { + return false; + } + } else if (!first.equals(other.first)) { + return false; + } + if (second == null) { + if (other.second != null) { + return false; + } + } else if (!second.equals(other.second)) { + return false; + } + return true; + } + + public String getFirst() { + return first; + } + + public void setFirst(String first) { + this.first = first; + } + + public String getSecond() { + return second; + } + + public void setSecond(String second) { + this.second = second; + } +} \ No newline at end of file diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairSerializer.java b/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairSerializer.java new file mode 100644 index 0000000000..68afb6c193 --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairSerializer.java @@ -0,0 +1,25 @@ +package com.baeldung.jackson.serialization; + +import java.io.IOException; +import java.io.StringWriter; + +import com.baeldung.jackson.entities.MyPair; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class MyPairSerializer extends JsonSerializer { + + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public void serialize(MyPair value, JsonGenerator gen, + SerializerProvider serializers) throws IOException, + JsonProcessingException { + StringWriter writer = new StringWriter(); + mapper.writeValue(writer, value); + gen.writeFieldName(writer.toString()); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java new file mode 100644 index 0000000000..3be3981c9b --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java @@ -0,0 +1,63 @@ +package com.baeldung.jackson.deserialization; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.baeldung.jackson.entities.MyPair; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JacksonMapDeserializeTest { + + private Map map; + private Map cmap; + + @Test + public void whenSimpleMapDeserialize_thenCorrect() + throws JsonParseException, JsonMappingException, IOException { + + final String jsonInput = "{\"key\": \"value\"}"; + final ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() { + }; + + final Map map = mapper.readValue(jsonInput, typeRef); + + Assert.assertEquals("value", map.get("key")); + } + + @Test + public void whenObjectStringMapDeserialize_thenCorrect() + throws JsonParseException, JsonMappingException, IOException { + + final String jsonInput = "{\"Abbott and Costello\" : \"Comedy\"}"; + final ObjectMapper mapper = new ObjectMapper(); + + TypeReference> typeRef = new TypeReference>() { + }; + map = mapper.readValue(jsonInput, typeRef); + + Assert.assertEquals("Comedy", map.get(new MyPair("Abbott", "Costello"))); + } + + @Test + public void whenObjectObjectMapDeserialize_thenCorrect() + throws JsonParseException, JsonMappingException, IOException { + + final String jsonInput = "{\"Abbott and Costello\" : \"Comedy and 1940s\"}"; + final ObjectMapper mapper = new ObjectMapper(); + TypeReference> typeRef = new TypeReference>() { + }; + + cmap = mapper.readValue(jsonInput, typeRef); + + Assert.assertEquals(new MyPair("Comedy", "1940s"), + cmap.get(new MyPair("Abbott", "Costello"))); + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java new file mode 100644 index 0000000000..71ba698e8e --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java @@ -0,0 +1,71 @@ +package com.baeldung.jackson.serialization; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.baeldung.jackson.entities.MyPair; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.MapSerializer; + +public class JacksonMapSerializeTest { + + @JsonSerialize(keyUsing = MyPairSerializer.class) + private Map map; + + @JsonSerialize(keyUsing = MapSerializer.class) + private Map cmap; + + @JsonSerialize(keyUsing = MyPairSerializer.class) + private MyPair mapKey; + + @JsonSerialize(keyUsing = MyPairSerializer.class) + private MyPair mapValue; + + @Test + public void whenSimpleMapSerialize_thenCorrect() + throws JsonProcessingException { + + Map map = new HashMap(); + map.put("key", "value"); + + final ObjectMapper mapper = new ObjectMapper(); + final String jsonResult = mapper.writeValueAsString(map); + + Assert.assertEquals("{\"key\":\"value\"}", jsonResult); + } + + @Test + public void whenCustomObjectStringMapSerialize_thenCorrect() + throws JsonProcessingException { + + map = new HashMap(); + MyPair key = new MyPair("Abbott", "Costello"); + map.put(key, "Comedy"); + + final ObjectMapper mapper = new ObjectMapper(); + final String jsonResult = mapper.writeValueAsString(map); + + Assert.assertEquals("{\"Abbott and Costello\":\"Comedy\"}", jsonResult); + } + + @Test + public void whenCustomObjectObjectMapSerialize_thenCorrect() + throws JsonProcessingException { + + cmap = new HashMap(); + mapKey = new MyPair("Abbott", "Costello"); + mapValue = new MyPair("Comedy", "1940's"); + cmap.put(mapKey, mapValue); + + final ObjectMapper mapper = new ObjectMapper(); + final String jsonResult = mapper.writeValueAsString(cmap); + + Assert.assertEquals("{\"Abbott and Costello\":\"Comedy and 1940's\"}", + jsonResult); + } +} From c5806d4e058281142a0dbfee1abc2ec084c735ea Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Mon, 27 Mar 2017 08:46:04 -0500 Subject: [PATCH 193/291] BAEL-737 README (#1514) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md --- spring-jpa/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-jpa/README.md b/spring-jpa/README.md index 313865e3f8..70f4404f98 100644 --- a/spring-jpa/README.md +++ b/spring-jpa/README.md @@ -13,6 +13,7 @@ - [Hibernate Second-Level Cache](http://www.baeldung.com/hibernate-second-level-cache) - [Spring, Hibernate and a JNDI Datasource](http://www.baeldung.com/spring-persistence-jpa-jndi-datasource) - [Deleting Objects with Hibernate](http://www.baeldung.com/delete-with-hibernate) +- [Self-Contained Testing Using an In-Memory Database](http://www.baeldung.com/spring-jpa-test-in-memory-database) ### Eclipse Config After importing the project into Eclipse, you may see the following error: From 365d75a8d7aca4a380926724c0ebe75d4d1396d8 Mon Sep 17 00:00:00 2001 From: Nancy Bosecker Date: Mon, 27 Mar 2017 09:44:59 -0700 Subject: [PATCH 194/291] Jackson version updated (#1516) * Solr w Apache SolrJ * Solr w Apache SolrJ * updated test names and moved add to @before method * create apache-solrj module, moved code from spring-data-solr * More examples for indexing,delete,and query for solrj * More examples for indexing,delete,and query for solrj * Jackson Map Serialize/Deserialize * Jackson Map Serialize/Deserialize * Jackson version update --- jackson/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jackson/pom.xml b/jackson/pom.xml index 881ba8e24c..8e627c146b 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -195,7 +195,7 @@ - 2.8.6 + 2.8.7 1.7.21 From 1c1c557a399327fc1cf031357c6c041c817a6760 Mon Sep 17 00:00:00 2001 From: Danil Kornishev Date: Mon, 27 Mar 2017 15:21:03 -0400 Subject: [PATCH 195/291] Spring State Machine (#1493) * Neo4j cleanup * Neo4j cleanup * Neo4j cleanup x2 * State Machine Init * cleanup * White background, Java Util Logging * Change to Logging * Static import of asserts. rename test methods * fix attempt for S3 -> S4 * Remove awaitility. add teardown * fix attempt for S3 -> S4 * fix attempt for S3 -> S4 Final --- pom.xml | 1 + spring-state-machine/bpmn/forkjoin.bpmn | 116 ++++++++++++++++++ spring-state-machine/bpmn/img/forkjoin.png | Bin 0 -> 50788 bytes spring-state-machine/bpmn/img/simple.png | Bin 0 -> 22706 bytes spring-state-machine/bpmn/simple.bpmn | 76 ++++++++++++ spring-state-machine/pom.xml | 31 +++++ .../ApplicationReviewEvents.java | 5 + .../ApplicationReviewStates.java | 5 + .../ForkJoinStateMachineConfiguration.java | 74 +++++++++++ ...HierarchicalStateMachineConfiguration.java | 47 +++++++ .../JunctionStateMachineConfiguration.java | 60 +++++++++ .../SimpleEnumStateMachineConfiguration.java | 53 ++++++++ .../SimpleStateMachineConfiguration.java | 105 ++++++++++++++++ .../config/StateMachineListener.java | 16 +++ .../ForkJoinStateMachineTest.java | 45 +++++++ .../HierarchicalStateMachineTest.java | 37 ++++++ .../JunctionStateMachineTest.java | 24 ++++ .../statemachine/StateEnumMachineTest.java | 33 +++++ .../statemachine/StateMachineBuilderTest.java | 35 ++++++ .../spring/statemachine/StateMachineTest.java | 51 ++++++++ 20 files changed, 814 insertions(+) create mode 100644 spring-state-machine/bpmn/forkjoin.bpmn create mode 100644 spring-state-machine/bpmn/img/forkjoin.png create mode 100644 spring-state-machine/bpmn/img/simple.png create mode 100644 spring-state-machine/bpmn/simple.bpmn create mode 100644 spring-state-machine/pom.xml create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java create mode 100644 spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java create mode 100644 spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java diff --git a/pom.xml b/pom.xml index 0939ea91b8..6b4511e45b 100644 --- a/pom.xml +++ b/pom.xml @@ -189,6 +189,7 @@ spring-sleuth spring-social-login spring-spel + spring-state-machine spring-thymeleaf spring-userservice spring-zuul diff --git a/spring-state-machine/bpmn/forkjoin.bpmn b/spring-state-machine/bpmn/forkjoin.bpmn new file mode 100644 index 0000000000..0cb060f74b --- /dev/null +++ b/spring-state-machine/bpmn/forkjoin.bpmn @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-state-machine/bpmn/img/forkjoin.png b/spring-state-machine/bpmn/img/forkjoin.png new file mode 100644 index 0000000000000000000000000000000000000000..642ab6949d18b49012529d7c5b9b14f909c9d701 GIT binary patch literal 50788 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�gf@SIUg-QO`umQ3S)QlWiV3@kS`RLu_ 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 D__yV@ literal 0 HcmV?d00001 diff --git a/spring-state-machine/bpmn/img/simple.png b/spring-state-machine/bpmn/img/simple.png new file mode 100644 index 0000000000000000000000000000000000000000..7a79bf1d895a401b2b59d4b093e770f3546bc3d3 GIT binary patch literal 22706 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/spring-state-machine/bpmn/simple.bpmn b/spring-state-machine/bpmn/simple.bpmn new file mode 100644 index 0000000000..8ed463e9f9 --- /dev/null +++ b/spring-state-machine/bpmn/simple.bpmn @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-state-machine/pom.xml b/spring-state-machine/pom.xml new file mode 100644 index 0000000000..5393626083 --- /dev/null +++ b/spring-state-machine/pom.xml @@ -0,0 +1,31 @@ + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + + 4.0.0 + + baeldung-spring-state-machine + + 1.8 + 1.8 + + + + + org.springframework.statemachine + spring-statemachine-core + 1.2.3.RELEASE + + + junit + junit + 4.11 + test + + + \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java new file mode 100644 index 0000000000..971fc5dde7 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java @@ -0,0 +1,5 @@ +package com.baeldung.spring.stateMachine.applicationReview; + +public enum ApplicationReviewEvents { + APPROVE, REJECT +} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java new file mode 100644 index 0000000000..1df2db1f86 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java @@ -0,0 +1,5 @@ +package com.baeldung.spring.stateMachine.applicationReview; + +public enum ApplicationReviewStates { + PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED +} diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java new file mode 100644 index 0000000000..c55104a627 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java @@ -0,0 +1,74 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +@Configuration +@EnableStateMachine +public class ForkJoinStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .fork("SFork") + .join("SJoin") + .end("SF") + .and() + .withStates() + .parent("SFork") + .initial("Sub1-1") + .end("Sub1-2") + .and() + .withStates() + .parent("SFork") + .initial("Sub2-1") + .end("Sub2-2"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SFork").event("E1") + .and().withExternal() + .source("Sub1-1").target("Sub1-2").event("sub1") + .and().withExternal() + .source("Sub2-1").target("Sub2-2").event("sub2") + .and() + .withFork() + .source("SFork") + .target("Sub1-1") + .target("Sub2-1") + .and() + .withJoin() + .source("Sub1-2") + .source("Sub2-2") + .target("SJoin"); + } + + @Bean + public Guard mediumGuard() { + return (ctx) -> false; + } + + @Bean + public Guard highGuard() { + return (ctx) -> false; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java new file mode 100644 index 0000000000..708dbd3077 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java @@ -0,0 +1,47 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; + +@Configuration +@EnableStateMachine +public class HierarchicalStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .state("SI") + .end("SF") + .and() + .withStates() + .parent("SI") + .initial("SUB1") + .state("SUB2") + .end("SUBEND"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SF").event("end") + .and().withExternal() + .source("SUB1").target("SUB2").event("se1") + .and().withExternal() + .source("SUB2").target("SUBEND").event("s-end"); + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java new file mode 100644 index 0000000000..e1bae10fb7 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java @@ -0,0 +1,60 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +@Configuration +@EnableStateMachine +public class JunctionStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .junction("SJ") + .state("high") + .state("medium") + .state("low") + .end("SF"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("SJ").event("E1") + .and() + .withJunction() + .source("SJ") + .first("high", highGuard()) + .then("medium", mediumGuard()) + .last("low") + .and().withExternal() + .source("low").target("SF").event("end"); + } + + @Bean + public Guard mediumGuard() { + return (ctx) -> false; + } + + @Bean + public Guard highGuard() { + return (ctx) -> false; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java new file mode 100644 index 0000000000..4e11851644 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java @@ -0,0 +1,53 @@ +package com.baeldung.spring.stateMachine.config; + +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +import java.util.Arrays; +import java.util.HashSet; + +@Configuration +@EnableStateMachine +public class SimpleEnumStateMachineConfiguration extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(ApplicationReviewStates.PEER_REVIEW) + .state(ApplicationReviewStates.PRINCIPAL_REVIEW) + .end(ApplicationReviewStates.APPROVED) + .end(ApplicationReviewStates.REJECTED); + + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.PRINCIPAL_REVIEW).event(ApplicationReviewEvents.APPROVE) + .and().withExternal() + .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.APPROVED).event(ApplicationReviewEvents.APPROVE) + .and().withExternal() + .source(ApplicationReviewStates.PEER_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT) + .and().withExternal() + .source(ApplicationReviewStates.PRINCIPAL_REVIEW).target(ApplicationReviewStates.REJECTED).event(ApplicationReviewEvents.REJECT); + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java new file mode 100644 index 0000000000..bb7556f97f --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -0,0 +1,105 @@ +package com.baeldung.spring.stateMachine.config; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.logging.Logger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachine; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; + +@Configuration +@EnableStateMachine +public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapter { + + public static final Logger LOGGER = Logger.getLogger(SimpleStateMachineConfiguration.class.getName()); + + @Override + public void configure(StateMachineConfigurationConfigurer config) + throws Exception { + config + .withConfiguration() + .autoStartup(true) + .listener(new StateMachineListener()); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .end("SF") + .states(new HashSet<>(Arrays.asList("S1", "S2"))) + .state("S4", executeAction(), errorAction()) + .stateEntry("S3", entryAction()) + .stateDo("S3", executeAction()) + .stateExit("S3", exitAction()); + + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions.withExternal() + .source("SI").target("S1").event("E1").action(initAction()) + .and().withExternal() + .source("S1").target("S2").event("E2") + .and().withExternal() + .source("SI").target("S3").event("E3") + .and().withExternal() + .source("S3").target("S4").event("E4").and().withExternal().source("S4").target("SF").event("end").guard(simpleGuard()) + .and().withExternal() + .source("S2").target("SF").event("end"); + } + + @Bean + public Guard simpleGuard() { + return (ctx) -> { + int approvalCount = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); + return approvalCount > 0; + }; + } + + @Bean + public Action entryAction() { + return (ctx) -> { + LOGGER.info("Entry " + ctx.getTarget().getId()); + }; + } + + @Bean + public Action executeAction() { + return (ctx) -> { + LOGGER.info("Do " + ctx.getTarget().getId()); + int approvals = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); + approvals++; + ctx.getExtendedState().getVariables().put("approvalCount", approvals); + }; + } + + @Bean + public Action exitAction() { + return (ctx) -> { + LOGGER.info("Exit " + ctx.getSource().getId() + " -> " + ctx.getTarget().getId()); + }; + } + + @Bean + public Action errorAction() { + return (ctx) -> { + LOGGER.info("Error " + ctx.getSource().getId() + ctx.getException()); + }; + } + + @Bean + public Action initAction() { + return (ctx) -> { + LOGGER.info(ctx.getTarget().getId()); + }; + } +} \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java new file mode 100644 index 0000000000..bb7859c683 --- /dev/null +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.stateMachine.config; + +import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import org.springframework.statemachine.state.State; + +import java.util.logging.Logger; + +public class StateMachineListener extends StateMachineListenerAdapter { + + public static final Logger LOGGER = Logger.getLogger(StateMachineListener.class.getName()); + + @Override + public void stateChanged(State from, State to) { + LOGGER.info(String.format("Transitioned from %s to %s%n", from == null ? "none" : from.getId(), to.getId())); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java new file mode 100644 index 0000000000..416da5f0fe --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java @@ -0,0 +1,45 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.ForkJoinStateMachineConfiguration; + +public class ForkJoinStateMachineTest { + + @Test + public void whenForkStateEntered_thenMultipleSubStatesEntered() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + boolean success = stateMachine.sendEvent("E1"); + + assertTrue(success); + + assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); + } + + @Test + public void whenAllConfiguredJoinEntryStatesAreEntered_thenTransitionToJoinState() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + boolean success = stateMachine.sendEvent("E1"); + + assertTrue(success); + + assertTrue(Arrays.asList("SFork", "Sub1-1", "Sub2-1").containsAll(stateMachine.getState().getIds())); + + assertTrue(stateMachine.sendEvent("sub1")); + assertTrue(stateMachine.sendEvent("sub2")); + assertEquals("SJoin", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java new file mode 100644 index 0000000000..3557a63211 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.HierarchicalStateMachineConfiguration; + +public class HierarchicalStateMachineTest { + + @Test + public void whenTransitionToSubMachine_thenSubStateIsEntered() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(HierarchicalStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + + assertEquals(Arrays.asList("SI", "SUB1"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("se1"); + + assertEquals(Arrays.asList("SI", "SUB2"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("s-end"); + + assertEquals(Arrays.asList("SI", "SUBEND"), stateMachine.getState().getIds()); + + stateMachine.sendEvent("end"); + + assertEquals(1, stateMachine.getState().getIds().size()); + assertEquals("SF", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java new file mode 100644 index 0000000000..d0c1225c9b --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.stateMachine; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.JunctionStateMachineConfiguration; + +public class JunctionStateMachineTest { + + @Test + public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JunctionStateMachineConfiguration.class); + StateMachine stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + + stateMachine.sendEvent("E1"); + Assert.assertEquals("low", stateMachine.getState().getId()); + + stateMachine.sendEvent("end"); + Assert.assertEquals("SF", stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java new file mode 100644 index 0000000000..1fd7bd85f0 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java @@ -0,0 +1,33 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; +import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; +import com.baeldung.spring.stateMachine.config.SimpleEnumStateMachineConfiguration; + +public class StateEnumMachineTest { + + private StateMachine stateMachine; + + @Before + public void setUp() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleEnumStateMachineConfiguration.class); + stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + } + + @Test + public void whenStateMachineConfiguredWithEnums_thenStateMachineAcceptsEnumEvents() { + assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.APPROVE)); + assertEquals(ApplicationReviewStates.PRINCIPAL_REVIEW, stateMachine.getState().getId()); + assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.REJECT)); + assertEquals(ApplicationReviewStates.REJECTED, stateMachine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java new file mode 100644 index 0000000000..cdd1e951e0 --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java @@ -0,0 +1,35 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.config.StateMachineBuilder; + +public class StateMachineBuilderTest { + + @Test + public void whenUseStateMachineBuilder_thenBuildSuccessAndMachineWorks() throws Exception { + StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); + builder.configureStates().withStates() + .initial("SI") + .state("S1") + .end("SF"); + + builder.configureTransitions() + .withExternal() + .source("SI").target("S1").event("E1") + .and().withExternal() + .source("S1").target("SF").event("E2"); + + StateMachine machine = builder.build(); + + machine.start(); + + machine.sendEvent("E1"); + assertEquals("S1", machine.getState().getId()); + + machine.sendEvent("E2"); + assertEquals("SF", machine.getState().getId()); + } +} diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java new file mode 100644 index 0000000000..9409f66f4f --- /dev/null +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java @@ -0,0 +1,51 @@ +package com.baeldung.spring.stateMachine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.stateMachine.config.SimpleStateMachineConfiguration; + +public class StateMachineTest { + + private AnnotationConfigApplicationContext ctx; + private StateMachine stateMachine; + + @Before + public void setUp() { + ctx = new AnnotationConfigApplicationContext(SimpleStateMachineConfiguration.class); + stateMachine = ctx.getBean(StateMachine.class); + stateMachine.start(); + } + + @Test + public void whenSimpleStringStateMachineEvents_thenEndState() { + assertEquals("SI", stateMachine.getState().getId()); + + stateMachine.sendEvent("E1"); + assertEquals("S1", stateMachine.getState().getId()); + + stateMachine.sendEvent("E2"); + assertEquals("S2", stateMachine.getState().getId()); + } + + @Test + public void whenSimpleStringMachineActionState_thenActionExecuted() { + + stateMachine.sendEvent("E3"); + assertEquals("S3", stateMachine.getState().getId()); + + boolean acceptedE4 = stateMachine.sendEvent("E4"); + + assertTrue(acceptedE4); + assertEquals("S4", stateMachine.getState().getId()); + assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount")); + + stateMachine.sendEvent("end"); + assertEquals("SF", stateMachine.getState().getId()); + } +} From 6a0e1420649662bad2569bbc6186bf266fc32d1a Mon Sep 17 00:00:00 2001 From: Tomasz Sobala Date: Mon, 27 Mar 2017 21:28:15 +0200 Subject: [PATCH 196/291] BAEL-431 Exploring the Spring Boot TestRestTemplate (#1444) * injecting beans * XML-based configuration replaced with Java Config. * [BAEL-431] Exploring TestRestTemplate. * Revert of evaluation task "XML-based configuration replaced with Java Config." This reverts commit 66471cf0574c85f8ff514ec4caf5ba44ebba1a74. * Revert of evaluation task "injecting beans" This reverts commit d2ac20185e636245bc0ae0b4ccb952965de88e28. * [BAEL-431] fix to the tests in TestRestTemplateBasicLiveTest. --- spring-rest/pom.xml | 4 + .../client/TestRestTemplateBasicLiveTest.java | 118 ++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java diff --git a/spring-rest/pom.xml b/spring-rest/pom.xml index da26d8abe9..a9b208bcd2 100644 --- a/spring-rest/pom.xml +++ b/spring-rest/pom.xml @@ -29,6 +29,10 @@ org.springframework.boot spring-boot-devtools + + org.springframework.boot + spring-boot-test + diff --git a/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java b/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java new file mode 100644 index 0000000000..9f4319d857 --- /dev/null +++ b/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java @@ -0,0 +1,118 @@ +package org.baeldung.client; + +import okhttp3.Request; +import okhttp3.RequestBody; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import static org.baeldung.client.Consts.APPLICATION_PORT; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + +public class TestRestTemplateBasicLiveTest { + + private RestTemplate restTemplate; + private static final String FOO_RESOURCE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-rest/myfoos"; + private static final String URL_SECURED_BY_AUTHENTICATION = "http://browserspy.dk/password-ok.php"; + private static final String BASE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-rest"; + + @Before + public void beforeTest() { + restTemplate = new RestTemplate(); + } + + // GET + @Test + public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapper_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateBuilderWrapper_whenSendGetForEntity_thenStatusOk() { + RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); + restTemplateBuilder.build(); + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder); + ResponseEntity response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenRestTemplateWrapperWithCredentials_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate, "test", "test"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentials_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithBasicAuth_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = testRestTemplate.withBasicAuth("test", "test"). + getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + @Test + public void givenTestRestTemplateWithCredentialsAndEnabledCookies_whenSendGetForEntity_thenStatusOk() { + TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test", TestRestTemplate. + HttpClientOption.ENABLE_COOKIES); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + String.class); + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + } + + // HEAD + @Test + public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeaders() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + final HttpHeaders httpHeaders = testRestTemplate.headForHeaders(FOO_RESOURCE_URL); + assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON)); + } + + // POST + @Test + public void givenService_whenPostForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + Object response = testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class); + assertTrue(response.toString().contains("Success")); + } + + // PUT + @Test + public void givenService_whenPutForObject_thenCreatedObjectIsReturned() { + TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); + final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), + "{\"id\":1,\"name\":\"Jim\"}"); + final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); + testRestTemplate.put(URL_SECURED_BY_AUTHENTICATION, request, String.class); + } + +} From 0c8aa7e46deb161c6fbe863d9e5acb2f77685370 Mon Sep 17 00:00:00 2001 From: azrairshad Date: Mon, 27 Mar 2017 14:17:58 -0700 Subject: [PATCH 197/291] Added an example for array copy via stream (#1510) --- .../baeldung/arraycopy/ArrayCopyUtilTest.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java index 2c9a97c496..060f3c3109 100644 --- a/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java +++ b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java @@ -144,7 +144,31 @@ public class ArrayCopyUtilTest { //change in employees' element didn't change in the copied array Assert.assertFalse(copiedArray[0].getName().equals(employees[0].getName())); } - + + @Test + public void givenArraysOfNonPrimitiveType_whenCopiedViaStream_thenDoShallowCopy(){ + Employee[] copiedArray = Arrays.stream(employees).toArray(Employee[]::new); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == employees.length); + employees[0].setName(employees[0].getName()+"_Changed"); + //change in employees' element didn't change in the copied array + Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); + } + + @Test + public void givenArraysOfPrimitiveType_whenCopiedViaStream_thenSuccessful(){ + String[] strArray = {"orange", "red", "green'"}; + + String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new); + + Assert.assertNotNull(copiedArray); + Assert.assertTrue(copiedArray.length == strArray.length); + Assert.assertTrue(copiedArray[0] == strArray[0]); + Assert.assertTrue(copiedArray[1] == strArray[1]); + Assert.assertTrue(copiedArray[2] == strArray[2]); + } + private Address[] createAddressArray(){ Address[] addresses = new Address[1]; addresses[0] = createAddress(); From 85969c69d22e0d9313648d417bbdf6e51915fe9d Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 28 Mar 2017 08:17:00 +0200 Subject: [PATCH 198/291] State machine refactor (#1520) * State machine refactor * Add surefire plugin * Refactor --- spring-state-machine/pom.xml | 29 ++++++++++++++++++- .../ApplicationReviewEvents.java | 2 +- .../ApplicationReviewStates.java | 2 +- .../ForkJoinStateMachineConfiguration.java | 2 +- ...HierarchicalStateMachineConfiguration.java | 2 +- .../JunctionStateMachineConfiguration.java | 2 +- .../SimpleEnumStateMachineConfiguration.java | 12 ++------ .../SimpleStateMachineConfiguration.java | 2 +- .../config/StateMachineListener.java | 2 +- .../ForkJoinStateMachineTest.java | 13 ++++----- .../HierarchicalStateMachineTest.java | 12 ++++---- .../JunctionStateMachineTest.java | 5 ++-- .../statemachine/StateEnumMachineTest.java | 13 ++++----- .../statemachine/StateMachineBuilderTest.java | 2 +- ....java => StateMachineIntegrationTest.java} | 13 ++++----- spring-zuul/pom.xml | 1 - 16 files changed, 65 insertions(+), 49 deletions(-) rename spring-state-machine/src/test/java/com/baeldung/spring/statemachine/{StateMachineTest.java => StateMachineIntegrationTest.java} (88%) diff --git a/spring-state-machine/pom.xml b/spring-state-machine/pom.xml index 5393626083..bec03c39e8 100644 --- a/spring-state-machine/pom.xml +++ b/spring-state-machine/pom.xml @@ -9,7 +9,7 @@ 4.0.0 - baeldung-spring-state-machine + spring-state-machine 1.8 1.8 @@ -27,5 +27,32 @@ 4.11 test + + + com.jayway.awaitility + awaitility + 1.7.0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + \ No newline at end of file diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java index 971fc5dde7..300bd6027e 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewEvents.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.applicationReview; +package com.baeldung.spring.statemachine.applicationreview; public enum ApplicationReviewEvents { APPROVE, REJECT diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java index 1df2db1f86..3d173e7471 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/applicationreview/ApplicationReviewStates.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.applicationReview; +package com.baeldung.spring.statemachine.applicationreview; public enum ApplicationReviewStates { PEER_REVIEW, PRINCIPAL_REVIEW, APPROVED, REJECTED diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java index c55104a627..3a3e632c51 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/ForkJoinStateMachineConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java index 708dbd3077..2bf9405c39 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/HierarchicalStateMachineConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; import org.springframework.context.annotation.Configuration; import org.springframework.statemachine.config.EnableStateMachine; diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java index e1bae10fb7..2f48a9dbb5 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/JunctionStateMachineConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java index 4e11851644..5339dea7d0 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleEnumStateMachineConfiguration.java @@ -1,19 +1,13 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; -import org.springframework.context.annotation.Bean; +import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents; +import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates; import org.springframework.context.annotation.Configuration; -import org.springframework.statemachine.action.Action; import org.springframework.statemachine.config.EnableStateMachine; import org.springframework.statemachine.config.StateMachineConfigurerAdapter; import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; -import org.springframework.statemachine.guard.Guard; - -import java.util.Arrays; -import java.util.HashSet; @Configuration @EnableStateMachine diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java index bb7556f97f..e9b448f6e7 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; import java.util.Arrays; import java.util.HashSet; diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java index bb7859c683..47a274404e 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/StateMachineListener.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine.config; +package com.baeldung.spring.statemachine.config; import org.springframework.statemachine.listener.StateMachineListenerAdapter; import org.springframework.statemachine.state.State; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java index 416da5f0fe..7b4b1928ea 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java @@ -1,15 +1,14 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; +package com.baeldung.spring.statemachine; +import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; -import com.baeldung.spring.stateMachine.config.ForkJoinStateMachineConfiguration; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class ForkJoinStateMachineTest { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java index 3557a63211..d2944be173 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java @@ -1,14 +1,14 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; +package com.baeldung.spring.statemachine; +import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; -import com.baeldung.spring.stateMachine.config.HierarchicalStateMachineConfiguration; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + public class HierarchicalStateMachineTest { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java index d0c1225c9b..f01683638b 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java @@ -1,17 +1,16 @@ -package com.baeldung.spring.stateMachine; +package com.baeldung.spring.statemachine; import org.junit.Assert; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; -import com.baeldung.spring.stateMachine.config.JunctionStateMachineConfiguration; public class JunctionStateMachineTest { @Test public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JunctionStateMachineConfiguration.class); + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration.class); StateMachine stateMachine = ctx.getBean(StateMachine.class); stateMachine.start(); diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java index 1fd7bd85f0..257ed8768c 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java @@ -1,16 +1,15 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +package com.baeldung.spring.statemachine; +import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents; +import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates; +import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; import org.junit.Before; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewEvents; -import com.baeldung.spring.stateMachine.applicationReview.ApplicationReviewStates; -import com.baeldung.spring.stateMachine.config.SimpleEnumStateMachineConfiguration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class StateEnumMachineTest { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java index cdd1e951e0..a5e4d07f18 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineBuilderTest.java @@ -1,4 +1,4 @@ -package com.baeldung.spring.stateMachine; +package com.baeldung.spring.statemachine; import static org.junit.Assert.assertEquals; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java similarity index 88% rename from spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java rename to spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index 9409f66f4f..d7b26eeb97 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -1,16 +1,15 @@ -package com.baeldung.spring.stateMachine; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +package com.baeldung.spring.statemachine; +import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; import org.junit.Before; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; -import com.baeldung.spring.stateMachine.config.SimpleStateMachineConfiguration; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class StateMachineTest { +public class StateMachineIntegrationTest { private AnnotationConfigApplicationContext ctx; private StateMachine stateMachine; @@ -34,7 +33,7 @@ public class StateMachineTest { } @Test - public void whenSimpleStringMachineActionState_thenActionExecuted() { + public void whenSimpleStringMachineActionState_thenActionExecuted() throws InterruptedException { stateMachine.sendEvent("E3"); assertEquals("S3", stateMachine.getState().getId()); diff --git a/spring-zuul/pom.xml b/spring-zuul/pom.xml index 50b20b8791..02fe589a3a 100644 --- a/spring-zuul/pom.xml +++ b/spring-zuul/pom.xml @@ -45,7 +45,6 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} true From a18d779294b7c023f4167774ec811e2cf331955d Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Tue, 28 Mar 2017 17:56:57 +0800 Subject: [PATCH 199/291] BAEL-636: add standalone deployment (#1521) --- spring-5/pom.xml | 7 -- .../com/baeldung/functional/RootServlet.java | 87 +++++++++++++++++++ .../java/com/baeldung/web/FooController.java | 3 +- spring-5/src/main/webapp/WEB-INF/web.xml | 21 +++++ 4 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 spring-5/src/main/java/com/baeldung/functional/RootServlet.java create mode 100644 spring-5/src/main/webapp/WEB-INF/web.xml diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 59bead4b73..6c52e6c8cc 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -40,13 +40,6 @@ spring-boot-starter-webflux - - - io.projectreactor - reactor-core - 3.0.6.BUILD-SNAPSHOT - - org.apache.commons diff --git a/spring-5/src/main/java/com/baeldung/functional/RootServlet.java b/spring-5/src/main/java/com/baeldung/functional/RootServlet.java new file mode 100644 index 0000000000..457206221b --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/RootServlet.java @@ -0,0 +1,87 @@ +package com.baeldung.functional; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.http.server.reactive.ServletHttpHandlerAdapter; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicLong; + +import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers; +import static org.springframework.web.reactive.function.BodyExtractors.toFormData; +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.RequestPredicates.*; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +public class RootServlet extends ServletHttpHandlerAdapter { + + public RootServlet() { + this(WebHttpHandlerBuilder + .webHandler(toHttpHandler(routingFunction())) + .prependFilter(new IndexRewriteFilter()) + .build()); + } + + private RootServlet(HttpHandler httpHandler) { + super(httpHandler); + } + + private static final Actor BRAD_PITT = new Actor("Brad", "Pitt"); + private static final Actor TOM_HANKS = new Actor("Tom", "Hanks"); + private static final List actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS)); + + private static RouterFunction routingFunction() { + + return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))) + .andRoute(POST("/login"), serverRequest -> serverRequest + .body(toFormData()) + .map(MultiValueMap::toSingleValueMap) + .map(formData -> { + System.out.println("form data: " + formData.toString()); + if ("baeldung".equals(formData.get("user")) && "you_know_what_to_do".equals(formData.get("token"))) { + return ok() + .body(Mono.just("welcome back!"), String.class) + .block(); + } + return ServerResponse + .badRequest() + .build() + .block(); + })) + .andRoute(POST("/upload"), serverRequest -> serverRequest + .body(toDataBuffers()) + .collectList() + .map(dataBuffers -> { + AtomicLong atomicLong = new AtomicLong(0); + dataBuffers.forEach(d -> atomicLong.addAndGet(d + .asByteBuffer() + .array().length)); + System.out.println("data length:" + atomicLong.get()); + return ok() + .body(fromObject(atomicLong.toString())) + .block(); + })) + .and(RouterFunctions.resources("/files/**", new ClassPathResource("files/"))) + .andNest(path("/actor"), route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest + .bodyToMono(Actor.class) + .doOnNext(actors::add) + .then(ok().build()))) + .filter((request, next) -> { + System.out.println("Before handler invocation: " + request.path()); + return next.handle(request); + }); + + } + +} diff --git a/spring-5/src/main/java/com/baeldung/web/FooController.java b/spring-5/src/main/java/com/baeldung/web/FooController.java index de6928033e..d0b69e707e 100644 --- a/spring-5/src/main/java/com/baeldung/web/FooController.java +++ b/spring-5/src/main/java/com/baeldung/web/FooController.java @@ -1,6 +1,7 @@ package com.baeldung.web; import java.util.List; +import java.util.Optional; import javax.validation.constraints.Max; import javax.validation.constraints.Min; @@ -33,7 +34,7 @@ public class FooController { @ResponseBody @Validated public Foo findById(@PathVariable @Min(0) final long id) { - return repo.findOne(id); + return repo.findOne(id).orElse(null); } @RequestMapping(method = RequestMethod.GET) diff --git a/spring-5/src/main/webapp/WEB-INF/web.xml b/spring-5/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..bfcf43dad2 --- /dev/null +++ b/spring-5/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + Spring Functional Application + + + functional + com.baeldung.functional.RootServlet + 1 + true + + + functional + / + + + + \ No newline at end of file From 0bc9bfbacbd10b0673a65ec52a0293da2db7f6ff Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Tue, 28 Mar 2017 19:50:03 +0800 Subject: [PATCH 200/291] BAEL-636: register servlet using java config (#1525) --- .../FunctionalSpringBootApplication.java | 87 +++++++++++++++++++ .../com/baeldung/functional/RootServlet.java | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 spring-5/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java diff --git a/spring-5/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java b/spring-5/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java new file mode 100644 index 0000000000..258a23a2bf --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/functional/FunctionalSpringBootApplication.java @@ -0,0 +1,87 @@ +package com.baeldung.functional; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; +import reactor.core.publisher.Flux; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.server.RequestPredicates.*; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +@SpringBootApplication +@ComponentScan(basePackages = { "com.baeldung.functional" }) +public class FunctionalSpringBootApplication { + + private static final Actor BRAD_PITT = new Actor("Brad", "Pitt"); + private static final Actor TOM_HANKS = new Actor("Tom", "Hanks"); + private static final List actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS)); + + private RouterFunction routingFunction() { + FormHandler formHandler = new FormHandler(); + + RouterFunction restfulRouter = route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest + .bodyToMono(Actor.class) + .doOnNext(actors::add) + .then(ok().build())); + + return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))) + .andRoute(POST("/login"), formHandler::handleLogin) + .andRoute(POST("/upload"), formHandler::handleUpload) + .and(RouterFunctions.resources("/files/**", new ClassPathResource("files/"))) + .andNest(path("/actor"), restfulRouter) + .filter((request, next) -> { + System.out.println("Before handler invocation: " + request.path()); + return next.handle(request); + }); + } + + @Bean + public ServletRegistrationBean servletRegistrationBean() throws Exception { + HttpHandler httpHandler = WebHttpHandlerBuilder + .webHandler(toHttpHandler(routingFunction())) + .prependFilter(new IndexRewriteFilter()) + .build(); + ServletRegistrationBean registrationBean = new ServletRegistrationBean<>(new RootServlet(httpHandler), "/"); + registrationBean.setLoadOnStartup(1); + registrationBean.setAsyncSupported(true); + return registrationBean; + } + + @Configuration + @EnableWebSecurity + @Profile("!https") + static class SecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(final HttpSecurity http) throws Exception { + http + .authorizeRequests() + .anyRequest() + .permitAll(); + } + } + + public static void main(String[] args) { + SpringApplication.run(FunctionalSpringBootApplication.class, args); + } + +} diff --git a/spring-5/src/main/java/com/baeldung/functional/RootServlet.java b/spring-5/src/main/java/com/baeldung/functional/RootServlet.java index 457206221b..54892c829f 100644 --- a/spring-5/src/main/java/com/baeldung/functional/RootServlet.java +++ b/spring-5/src/main/java/com/baeldung/functional/RootServlet.java @@ -33,7 +33,7 @@ public class RootServlet extends ServletHttpHandlerAdapter { .build()); } - private RootServlet(HttpHandler httpHandler) { + RootServlet(HttpHandler httpHandler) { super(httpHandler); } From 70d8fecc54c9c7dd5812a6e3c3329e81e3f15c49 Mon Sep 17 00:00:00 2001 From: Parth Joshi Date: Tue, 28 Mar 2017 18:29:33 +0530 Subject: [PATCH 201/291] Comparator comparing (#1515) * Initial commit for Comparator.comparing article. * Changes in the code as per suggestions in review. * Change in test names as per suggestions... * Changes in tests names for nullFirst and nullLast cases * clean up. --- .../java8/comparator/Java8ComparatorTest.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java index 57e3898274..ebcbb7a3fc 100644 --- a/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java +++ b/core-java/src/test/java/com/baeldung/java8/comparator/Java8ComparatorTest.java @@ -76,6 +76,15 @@ public class Java8ComparatorTest { // System.out.println(Arrays.toString(employees)); assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); } + + @Test + public void whenReversed_thenSortedByNameDesc() { + Comparator employeeNameComparator = Comparator.comparing(Employee::getName); + Comparator employeeNameComparatorReversed = employeeNameComparator.reversed(); + Arrays.sort(employees, employeeNameComparatorReversed); +// System.out.println(Arrays.toString(employees)); + assertTrue(Arrays.equals(employees, sortedEmployeesByNameDesc)); + } @Test public void whenComparingInt_thenSortedByAge() { @@ -153,4 +162,6 @@ public class Java8ComparatorTest { assertTrue(Arrays.equals(someMoreEmployees, sortedEmployeesByNameAge)); } -} \ No newline at end of file + +} + From ef91c379b74f6645f53c348f96234bf19df44f4f Mon Sep 17 00:00:00 2001 From: ahamedm Date: Tue, 28 Mar 2017 18:50:00 +0400 Subject: [PATCH 202/291] BAEL-696 Implement OR in the REST API Query Language (#1518) * Dependency Injection Types, XML-Config, Java-Config, Test Classes * Formatting done with Formatter Configuration in Eclipse * REST Query Lang - Adv Search Ops - Improvement - C1 * REST Query Lang - Adv Search Ops - Improvement - C2 * BAEL-696 Code formatting * REST Query Lang - Adv Search Ops - Improvement - C3 * BAEL-636: add standalone deployment (#1521) * BAEL-696 Formatting --- .gitignore | 2 + .../persistence/IEnhancedSpecification.java | 10 - .../dao/GenericSpecificationsBuilder.java | 98 +++--- .../dao/UserSpecificationsBuilder.java | 18 +- .../web/controller/UserController.java | 298 +++++++++--------- .../baeldung/web/util/SearchOperation.java | 8 +- .../baeldung/web/util/SpecSearchCriteria.java | 14 +- .../JPASpecificationIntegrationTest.java | 23 +- 8 files changed, 250 insertions(+), 221 deletions(-) delete mode 100644 spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java diff --git a/.gitignore b/.gitignore index 784627b616..f3fa30f3e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*/bin/* + *.class # Package Files # diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java deleted file mode 100644 index 58d08a161e..0000000000 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/IEnhancedSpecification.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.baeldung.persistence; - -import org.springframework.data.jpa.domain.Specification; - -public interface IEnhancedSpecification extends Specification { - - default boolean isOfLowPrecedence() { - return false; - } -} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java index 4936c2e1c1..45c015f233 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java @@ -1,6 +1,7 @@ package org.baeldung.persistence.dao; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -12,53 +13,64 @@ import org.springframework.data.jpa.domain.Specifications; public class GenericSpecificationsBuilder { - private final List params; + private final List params; - public GenericSpecificationsBuilder() { - this.params = new ArrayList<>(); - } + public GenericSpecificationsBuilder() { + this.params = new ArrayList<>(); + } - public final GenericSpecificationsBuilder with(final String key, final String operation, final Object value, - final String prefix, final String suffix) { - return with(null, key, operation, value, prefix, suffix); - } + public final GenericSpecificationsBuilder with(final String key, final String operation, final Object value, final String prefix, final String suffix) { + return with(null, key, operation, value, prefix, suffix); + } - public final GenericSpecificationsBuilder with(final String precedenceIndicator, final String key, - final String operation, final Object value, final String prefix, final String suffix) { - SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); - if (op != null) { - if (op == SearchOperation.EQUALITY) // the operation may be complex operation - { - final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX); - final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + public final GenericSpecificationsBuilder with(final String precedenceIndicator, final String key, final String operation, final Object value, final String prefix, final String suffix) { + SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); + if (op != null) { + if (op == SearchOperation.EQUALITY) // the operation may be complex operation + { + final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX); - if (startWithAsterisk && endWithAsterisk) { - op = SearchOperation.CONTAINS; - } else if (startWithAsterisk) { - op = SearchOperation.ENDS_WITH; - } else if (endWithAsterisk) { - op = SearchOperation.STARTS_WITH; - } - } - params.add(new SpecSearchCriteria(precedenceIndicator, key, op, value)); - } - return this; - } + if (startWithAsterisk && endWithAsterisk) { + op = SearchOperation.CONTAINS; + } else if (startWithAsterisk) { + op = SearchOperation.ENDS_WITH; + } else if (endWithAsterisk) { + op = SearchOperation.STARTS_WITH; + } + } + params.add(new SpecSearchCriteria(precedenceIndicator, key, op, value)); + } + return this; + } - public Specification build(Function> converter) { + public Specification build(Function> converter) { + + if (params.size() == 0) { + return null; + } + + params.sort(Comparator.comparing(SpecSearchCriteria::isOrPredicate)); + + final List> specs = params + .stream() + .map(converter) + .collect(Collectors.toCollection(ArrayList::new)); + + Specification result = specs.get(0); + + for (int idx = 1; idx < specs.size(); idx++) { + result = params + .get(idx) + .isOrPredicate() + ? Specifications + .where(result) + .or(specs.get(idx)) + : Specifications + .where(result) + .and(specs.get(idx)); + } + return result; + } - if (params.size() == 0) - return null; - - params.sort((spec0, spec1) -> Boolean.compare(spec0.isLowPrecedence(), spec1.isLowPrecedence())); - - final List> specs = params.stream().map(converter).collect(Collectors.toCollection(ArrayList::new)); - - Specification result = specs.get(0); - - for (int idx = 1; idx < specs.size(); idx++) { - result=params.get(idx).isLowPrecedence()? Specifications.where(result).or(specs.get(idx)): Specifications.where(result).and(specs.get(idx)); - } - return result; - } } diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java index 8a10163f51..bbcb521241 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java @@ -1,14 +1,15 @@ package org.baeldung.persistence.dao; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + import org.baeldung.persistence.model.User; import org.baeldung.web.util.SearchOperation; import org.baeldung.web.util.SpecSearchCriteria; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specifications; -import java.util.ArrayList; -import java.util.List; - public final class UserSpecificationsBuilder { private final List params; @@ -48,14 +49,17 @@ public final class UserSpecificationsBuilder { if (params.size() == 0) return null; - params.sort((spec0, spec1) -> { - return Boolean.compare(spec0.isLowPrecedence(), spec1.isLowPrecedence()); - }); + params.sort(Comparator.comparing(SpecSearchCriteria::isOrPredicate)); Specification result = new UserSpecification(params.get(0)); for (int i = 1; i < params.size(); i++) { - result = params.get(i).isLowPrecedence() ? Specifications.where(result).or(new UserSpecification(params.get(i))) : Specifications.where(result).and(new UserSpecification(params.get(i))); + result = params.get(i) + .isOrPredicate() + ? Specifications.where(result) + .or(new UserSpecification(params.get(i))) + : Specifications.where(result) + .and(new UserSpecification(params.get(i))); } diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java index fff089a62b..4c21d9836d 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java @@ -1,141 +1,157 @@ -package org.baeldung.web.controller; - -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import com.querydsl.core.types.Predicate; -import com.querydsl.core.types.dsl.BooleanExpression; -import cz.jirutka.rsql.parser.RSQLParser; -import cz.jirutka.rsql.parser.ast.Node; -import org.baeldung.persistence.dao.*; -import org.baeldung.persistence.dao.rsql.CustomRsqlVisitor; -import org.baeldung.persistence.model.MyUser; -import org.baeldung.persistence.model.User; -import org.baeldung.web.util.SearchCriteria; -import org.baeldung.web.util.SearchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.querydsl.binding.QuerydslPredicate; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -//@EnableSpringDataWebSupport -@Controller -@RequestMapping(value = "/auth/") -public class UserController { - - @Autowired - private IUserDAO service; - - @Autowired - private UserRepository dao; - - @Autowired - private MyUserRepository myUserRepository; - - public UserController() { - super(); - } - - // API - READ - - @RequestMapping(method = RequestMethod.GET, value = "/users") - @ResponseBody - public List findAll(@RequestParam(value = "search", required = false) final String search) { - final List params = new ArrayList(); - if (search != null) { - final Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); - final Matcher matcher = pattern.matcher(search + ","); - while (matcher.find()) { - params.add(new SearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3))); - } - } - return service.searchUser(params); - } - - @RequestMapping(method = RequestMethod.GET, value = "/users/spec") - @ResponseBody - public List findAllBySpecification(@RequestParam(value = "search") final String search) { - final UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - final String operationSetExper = Joiner.on("|").join(SearchOperation.SIMPLE_OPERATION_SET); - final Pattern pattern = Pattern.compile("(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); - final Matcher matcher = pattern.matcher(search + ","); - while (matcher.find()) { - builder.with(matcher.group(1), matcher.group(2), matcher.group(4), matcher.group(3), matcher.group(5)); - } - - final Specification spec = builder.build(); - return dao.findAll(spec); - } - - @RequestMapping(method = RequestMethod.GET, value = "/users/espec") - @ResponseBody - public List findAllByOptionalSpecification(@RequestParam(value = "search") final String search) { - final Specification spec = resolveSpecification(search); - return dao.findAll(spec); - } - - protected Specification resolveSpecification(String searchParameters) { - - final UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - final String operationSetExper = Joiner.on("|").join(SearchOperation.SIMPLE_OPERATION_SET); - final Pattern pattern = Pattern.compile("(\\p{Punct}?)(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); - final Matcher matcher = pattern.matcher(searchParameters + ","); - while (matcher.find()) { - builder.with(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(5), matcher.group(4), matcher.group(6)); - } - return builder.build(); - } - - @RequestMapping(method = RequestMethod.GET, value = "/myusers") - @ResponseBody - public Iterable findAllByQuerydsl(@RequestParam(value = "search") final String search) { - final MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder(); - if (search != null) { - final Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); - final Matcher matcher = pattern.matcher(search + ","); - while (matcher.find()) { - builder.with(matcher.group(1), matcher.group(2), matcher.group(3)); - } - } - final BooleanExpression exp = builder.build(); - return myUserRepository.findAll(exp); - } - - @RequestMapping(method = RequestMethod.GET, value = "/users/rsql") - @ResponseBody - public List findAllByRsql(@RequestParam(value = "search") final String search) { - final Node rootNode = new RSQLParser().parse(search); - final Specification spec = rootNode.accept(new CustomRsqlVisitor()); - return dao.findAll(spec); - } - - @RequestMapping(method = RequestMethod.GET, value = "/api/myusers") - @ResponseBody - public Iterable findAllByWebQuerydsl(@QuerydslPredicate(root = MyUser.class) final Predicate predicate) { - return myUserRepository.findAll(predicate); - } - - // API - WRITE - - @RequestMapping(method = RequestMethod.POST, value = "/users") - @ResponseStatus(HttpStatus.CREATED) - public void create(@RequestBody final User resource) { - Preconditions.checkNotNull(resource); - dao.save(resource); - } - - @RequestMapping(method = RequestMethod.POST, value = "/myusers") - @ResponseStatus(HttpStatus.CREATED) - public void addMyUser(@RequestBody final MyUser resource) { - Preconditions.checkNotNull(resource); - myUserRepository.save(resource); - - } - -} +package org.baeldung.web.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.baeldung.persistence.dao.IUserDAO; +import org.baeldung.persistence.dao.MyUserPredicatesBuilder; +import org.baeldung.persistence.dao.MyUserRepository; +import org.baeldung.persistence.dao.UserRepository; +import org.baeldung.persistence.dao.UserSpecificationsBuilder; +import org.baeldung.persistence.dao.rsql.CustomRsqlVisitor; +import org.baeldung.persistence.model.MyUser; +import org.baeldung.persistence.model.User; +import org.baeldung.web.util.SearchCriteria; +import org.baeldung.web.util.SearchOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.querydsl.binding.QuerydslPredicate; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.querydsl.core.types.Predicate; +import com.querydsl.core.types.dsl.BooleanExpression; + +import cz.jirutka.rsql.parser.RSQLParser; +import cz.jirutka.rsql.parser.ast.Node; + +//@EnableSpringDataWebSupport +@Controller +@RequestMapping(value = "/auth/") +public class UserController { + + @Autowired + private IUserDAO service; + + @Autowired + private UserRepository dao; + + @Autowired + private MyUserRepository myUserRepository; + + public UserController() { + super(); + } + + // API - READ + + @RequestMapping(method = RequestMethod.GET, value = "/users") + @ResponseBody + public List findAll(@RequestParam(value = "search", required = false) String search) { + List params = new ArrayList(); + if (search != null) { + Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); + Matcher matcher = pattern.matcher(search + ","); + while (matcher.find()) { + params.add(new SearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3))); + } + } + return service.searchUser(params); + } + + @RequestMapping(method = RequestMethod.GET, value = "/users/spec") + @ResponseBody + public List findAllBySpecification(@RequestParam(value = "search") String search) { + UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); + String operationSetExper = Joiner + .on("|") + .join(SearchOperation.SIMPLE_OPERATION_SET); + Pattern pattern = Pattern.compile("(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); + Matcher matcher = pattern.matcher(search + ","); + while (matcher.find()) { + builder.with(matcher.group(1), matcher.group(2), matcher.group(4), matcher.group(3), matcher.group(5)); + } + + Specification spec = builder.build(); + return dao.findAll(spec); + } + + @GetMapping(value = "/users/espec") + @ResponseBody + public List findAllByOrPredicate(@RequestParam(value = "search") String search) { + Specification spec = resolveSpecification(search); + return dao.findAll(spec); + } + + protected Specification resolveSpecification(String searchParameters) { + + UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); + String operationSetExper = Joiner + .on("|") + .join(SearchOperation.SIMPLE_OPERATION_SET); + Pattern pattern = Pattern.compile("(\\p{Punct}?)(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); + Matcher matcher = pattern.matcher(searchParameters + ","); + while (matcher.find()) { + builder.with(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(5), matcher.group(4), matcher.group(6)); + } + return builder.build(); + } + + @RequestMapping(method = RequestMethod.GET, value = "/myusers") + @ResponseBody + public Iterable findAllByQuerydsl(@RequestParam(value = "search") String search) { + MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder(); + if (search != null) { + Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); + Matcher matcher = pattern.matcher(search + ","); + while (matcher.find()) { + builder.with(matcher.group(1), matcher.group(2), matcher.group(3)); + } + } + BooleanExpression exp = builder.build(); + return myUserRepository.findAll(exp); + } + + @RequestMapping(method = RequestMethod.GET, value = "/users/rsql") + @ResponseBody + public List findAllByRsql(@RequestParam(value = "search") String search) { + Node rootNode = new RSQLParser().parse(search); + Specification spec = rootNode.accept(new CustomRsqlVisitor()); + return dao.findAll(spec); + } + + @RequestMapping(method = RequestMethod.GET, value = "/api/myusers") + @ResponseBody + public Iterable findAllByWebQuerydsl(@QuerydslPredicate(root = MyUser.class) Predicate predicate) { + return myUserRepository.findAll(predicate); + } + + // API - WRITE + + @RequestMapping(method = RequestMethod.POST, value = "/users") + @ResponseStatus(HttpStatus.CREATED) + public void create(@RequestBody User resource) { + Preconditions.checkNotNull(resource); + dao.save(resource); + } + + @RequestMapping(method = RequestMethod.POST, value = "/myusers") + @ResponseStatus(HttpStatus.CREATED) + public void addMyUser(@RequestBody MyUser resource) { + Preconditions.checkNotNull(resource); + myUserRepository.save(resource); + + } + +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java index 41a556c18a..fa09662201 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java @@ -4,10 +4,10 @@ public enum SearchOperation { EQUALITY, NEGATION, GREATER_THAN, LESS_THAN, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS; public static final String[] SIMPLE_OPERATION_SET = { ":", "!", ">", "<", "~" }; - - public static final String LOW_PRECEDENCE_INDICATOR="'"; - - public static final String ZERO_OR_MORE_REGEX="*"; + + public static final String OR_PREDICATE_FLAG = "'"; + + public static final String ZERO_OR_MORE_REGEX = "*"; public static SearchOperation getSimpleOperation(final char input) { switch (input) { diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java index 7dbb66edea..6b37fb579c 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java @@ -5,7 +5,7 @@ public class SpecSearchCriteria { private String key; private SearchOperation operation; private Object value; - private boolean lowPrecedence; + private boolean orPredicate; public SpecSearchCriteria() { @@ -18,9 +18,9 @@ public class SpecSearchCriteria { this.value = value; } - public SpecSearchCriteria(final String lowPrecedenceIndicator, final String key, final SearchOperation operation, final Object value) { + public SpecSearchCriteria(final String orPredicate, final String key, final SearchOperation operation, final Object value) { super(); - this.lowPrecedence = lowPrecedenceIndicator != null && lowPrecedenceIndicator.equals(SearchOperation.LOW_PRECEDENCE_INDICATOR); + this.orPredicate = orPredicate != null && orPredicate.equals(SearchOperation.OR_PREDICATE_FLAG); this.key = key; this.operation = operation; this.value = value; @@ -50,12 +50,12 @@ public class SpecSearchCriteria { this.value = value; } - public boolean isLowPrecedence() { - return lowPrecedence; + public boolean isOrPredicate() { + return orPredicate; } - public void setLowPrecedence(boolean lowPrecedence) { - this.lowPrecedence = lowPrecedence; + public void setOrPredicate(boolean orPredicate) { + this.orPredicate = orPredicate; } } diff --git a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java index e5c408bfdb..244e19db90 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java @@ -70,7 +70,9 @@ public class JPASpecificationIntegrationTest { public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.EQUALITY, "john")); final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe")); - final List results = repository.findAll(Specifications.where(spec).and(spec1)); + final List results = repository.findAll(Specifications + .where(spec) + .and(spec1)); assertThat(userJohn, isIn(results)); assertThat(userTom, not(isIn(results))); @@ -80,10 +82,13 @@ public class JPASpecificationIntegrationTest { public void givenFirstOrLastName_whenGettingListOfUsers_thenCorrect() { UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - final SpecSearchCriteria spec = new SpecSearchCriteria("'", "firstName", SearchOperation.EQUALITY, "john"); - final SpecSearchCriteria spec1 = new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe"); + SpecSearchCriteria spec = new SpecSearchCriteria("'", "firstName", SearchOperation.EQUALITY, "john"); + SpecSearchCriteria spec1 = new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe"); - final List results = repository.findAll(builder.with(spec1).with(spec).build()); + List results = repository.findAll(builder + .with(spec1) + .with(spec) + .build()); assertThat(results, hasSize(2)); assertThat(userJohn, isIn(results)); @@ -97,7 +102,8 @@ public class JPASpecificationIntegrationTest { builder.with("'", "firstName", ":", "john", null, null); builder.with(null, "lastName", ":", "doe", null, null); - final List results = repository.findAll(builder.build(converter)); + List results = repository.findAll(builder.build(converter)); + assertThat(results, hasSize(2)); assertThat(userJohn, isIn(results)); assertThat(userTom, isIn(results)); @@ -116,7 +122,6 @@ public class JPASpecificationIntegrationTest { public void givenMinAge_whenGettingListOfUsers_thenCorrect() { final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "25")); final List results = repository.findAll(Specifications.where(spec)); - assertThat(userTom, isIn(results)); assertThat(userJohn, not(isIn(results))); } @@ -125,7 +130,6 @@ public class JPASpecificationIntegrationTest { public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.STARTS_WITH, "jo")); final List results = repository.findAll(spec); - assertThat(userJohn, isIn(results)); assertThat(userTom, not(isIn(results))); } @@ -134,7 +138,6 @@ public class JPASpecificationIntegrationTest { public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("firstName", SearchOperation.ENDS_WITH, "n")); final List results = repository.findAll(spec); - assertThat(userJohn, isIn(results)); assertThat(userTom, not(isIn(results))); } @@ -152,7 +155,9 @@ public class JPASpecificationIntegrationTest { public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { final UserSpecification spec = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.GREATER_THAN, "20")); final UserSpecification spec1 = new UserSpecification(new SpecSearchCriteria("age", SearchOperation.LESS_THAN, "25")); - final List results = repository.findAll(Specifications.where(spec).and(spec1)); + final List results = repository.findAll(Specifications + .where(spec) + .and(spec1)); assertThat(userJohn, isIn(results)); assertThat(userTom, not(isIn(results))); From 17042f0420772d036b8d24dab1c6644ec918a8a7 Mon Sep 17 00:00:00 2001 From: Chandravadan S Date: Tue, 28 Mar 2017 21:01:25 +0530 Subject: [PATCH 203/291] BAEL-732: String to enum (#1526) --- .../com/baeldung/enums/PizzaUnitTest.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java b/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java index 6cf6ad3551..db7aa6d920 100644 --- a/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java +++ b/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java @@ -1,12 +1,14 @@ package com.baeldung.enums; -import org.junit.Test; +import static junit.framework.TestCase.assertTrue; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; -import static junit.framework.TestCase.assertTrue; +import org.junit.Test; + +import com.baeldung.enums.Pizza.PizzaStatusEnum; public class PizzaUnitTest { @@ -75,5 +77,25 @@ public class PizzaUnitTest { pz.deliver(); assertTrue(pz.getStatus() == Pizza.PizzaStatusEnum.DELIVERED); } + + @Test + public void givenValidEnumValueAsString_whenConvertedIntoEnum_thenGetsConvertedCorrectly() { + String pizzaEnumValue = "READY"; + PizzaStatusEnum pizzaStatusEnum = PizzaStatusEnum.valueOf(pizzaEnumValue); + assertTrue(pizzaStatusEnum == PizzaStatusEnum.READY); + } + + @Test(expected = IllegalArgumentException.class) + public void givenInvalidEnumValueCaseWiseAsString_whenConvertedIntoEnum_thenThrowsException() { + String pizzaEnumValue = "rEAdY"; + PizzaStatusEnum pizzaStatusEnum = PizzaStatusEnum.valueOf(pizzaEnumValue); + } + + @Test(expected = IllegalArgumentException.class) + public void givenInvalidEnumValueContentWiseAsString_whenConvertedIntoEnum_thenThrowsException() { + String pizzaEnumValue = "invalid"; + PizzaStatusEnum pizzaStatusEnum = PizzaStatusEnum.valueOf(pizzaEnumValue); + } + } From 6e2dcfcf5903d2e273ef48507e8c3daf3f0d8f3b Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 28 Mar 2017 22:45:46 +0200 Subject: [PATCH 204/291] Refactor PizzaUnitTest (#1527) --- .../test/java/com/baeldung/enums/PizzaUnitTest.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java b/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java index db7aa6d920..35aa07821c 100644 --- a/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java +++ b/core-java/src/test/java/com/baeldung/enums/PizzaUnitTest.java @@ -1,14 +1,13 @@ package com.baeldung.enums; -import static junit.framework.TestCase.assertTrue; +import com.baeldung.enums.Pizza.PizzaStatusEnum; +import org.junit.Test; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; -import org.junit.Test; - -import com.baeldung.enums.Pizza.PizzaStatusEnum; +import static junit.framework.TestCase.assertTrue; public class PizzaUnitTest { @@ -71,7 +70,7 @@ public class PizzaUnitTest { } @Test - public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() { + public void whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() { Pizza pz = new Pizza(); pz.setStatus(Pizza.PizzaStatusEnum.READY); pz.deliver(); @@ -79,14 +78,14 @@ public class PizzaUnitTest { } @Test - public void givenValidEnumValueAsString_whenConvertedIntoEnum_thenGetsConvertedCorrectly() { + public void whenConvertedIntoEnum_thenGetsConvertedCorrectly() { String pizzaEnumValue = "READY"; PizzaStatusEnum pizzaStatusEnum = PizzaStatusEnum.valueOf(pizzaEnumValue); assertTrue(pizzaStatusEnum == PizzaStatusEnum.READY); } @Test(expected = IllegalArgumentException.class) - public void givenInvalidEnumValueCaseWiseAsString_whenConvertedIntoEnum_thenThrowsException() { + public void whenConvertedIntoEnum_thenThrowsException() { String pizzaEnumValue = "rEAdY"; PizzaStatusEnum pizzaStatusEnum = PizzaStatusEnum.valueOf(pizzaEnumValue); } From 6fe778979a3b7fce3ff5a483a1544e8eba360deb Mon Sep 17 00:00:00 2001 From: Devendra Tiwari Date: Wed, 29 Mar 2017 02:18:47 +0530 Subject: [PATCH 205/291] Guide to Guava | common.util.concurrent (#1528) Code and Tests for common.util.concurrent package --- .../tutorial/AtomicLongMapTutorials.java | 28 ++++++++ .../guava/tutorial/MonitorExample.java | 29 +++++++++ guava21/src/test/java/AtomicLongMapTests.java | 64 +++++++++++++++++++ guava21/src/test/java/MonitorUnitTests.java | 61 ++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java create mode 100644 guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java create mode 100644 guava21/src/test/java/AtomicLongMapTests.java create mode 100644 guava21/src/test/java/MonitorUnitTests.java diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java b/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java new file mode 100644 index 0000000000..69ad04ad9c --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java @@ -0,0 +1,28 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.util.concurrent.AtomicLongMap; + +public class AtomicLongMapTutorials { + + private AtomicLongMap atomicLongMap; + + public AtomicLongMapTutorials(){ + atomicLongMap = AtomicLongMap.create(); + } + + + public void addKeys(){ + atomicLongMap.addAndGet("apple",250); + atomicLongMap.addAndGet("bat",350); + atomicLongMap.addAndGet("cat",450); + atomicLongMap.addAndGet("dog",550); + } + + public static void main(String[] args){ + AtomicLongMapTutorials atomicLongMapTutorials = new AtomicLongMapTutorials(); + atomicLongMapTutorials.addKeys(); + + System.out.println(atomicLongMapTutorials.atomicLongMap.get("2")); + } + +} diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java new file mode 100644 index 0000000000..2f316c293e --- /dev/null +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java @@ -0,0 +1,29 @@ +package com.baeldung.guava.tutorial; + +import com.google.common.util.concurrent.Monitor; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; + +public class MonitorExample { + private List students = new ArrayList(); + private static final int MAX_SIZE = 100; + + private Monitor monitor = new Monitor(); + + + public void addToCourse(String item) throws InterruptedException { + Monitor.Guard studentsBelowCapacity = monitor.newGuard(this::isStudentsCapacityUptoLimit); + monitor.enterWhen(studentsBelowCapacity); + try { + students.add(item); + } finally { + monitor.leave(); + } + } + + public Boolean isStudentsCapacityUptoLimit(){ + return students.size() > MAX_SIZE; + } +} diff --git a/guava21/src/test/java/AtomicLongMapTests.java b/guava21/src/test/java/AtomicLongMapTests.java new file mode 100644 index 0000000000..aad72907de --- /dev/null +++ b/guava21/src/test/java/AtomicLongMapTests.java @@ -0,0 +1,64 @@ +import com.google.common.util.concurrent.AtomicLongMap; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class AtomicLongMapTests { + + private static final String SPRING_COURSE_KEY = "Spring"; + private static final String HIBERNATE_COURSE_KEY = "hibernate"; + private static final String GUAVA_COURSE_KEY = "Guava"; + + AtomicLongMap courses = AtomicLongMap.create(); + + public void setUp(){ + courses.put(SPRING_COURSE_KEY, 1056); + courses.put(HIBERNATE_COURSE_KEY, 259); + courses.put(GUAVA_COURSE_KEY, 78); + } + + +@Test +public void accumulateAndGet_withLongBinaryOperator_thenSuccessful(){ + long noOfStudents = 56; + long oldValue = courses.get(SPRING_COURSE_KEY); + + long totalNotesRequired = courses.accumulateAndGet( + "Guava", + noOfStudents, + (x,y) -> (x * y)); + + assertEquals(totalNotesRequired, oldValue * noOfStudents ); +} + + @Test + public void getAndAccumulate_withLongBinaryOperator_thenSuccessful(){ + long noOfStudents = 56; + long beforeUpdate = courses.get(SPRING_COURSE_KEY); + + long onUpdate = courses.accumulateAndGet("Guava", + noOfStudents, + (x,y) -> (x * y) + ); + + long afterUpdate = courses.get(SPRING_COURSE_KEY); + + assertEquals(onUpdate, afterUpdate); + assertEquals(afterUpdate, beforeUpdate * noOfStudents); + } + +@Test +public void updateAndGet_withLongUnaryOperator_thenSuccessful(){ + long beforeUpdate = courses.get(SPRING_COURSE_KEY); + + long onUpdate = courses.updateAndGet( + "Guava", + (x) -> (x/2)); + + long afterUpdate = courses.get(SPRING_COURSE_KEY); + + assertEquals(onUpdate, afterUpdate); + assertEquals(afterUpdate, beforeUpdate/2); +} +} diff --git a/guava21/src/test/java/MonitorUnitTests.java b/guava21/src/test/java/MonitorUnitTests.java new file mode 100644 index 0000000000..6427072db9 --- /dev/null +++ b/guava21/src/test/java/MonitorUnitTests.java @@ -0,0 +1,61 @@ +import com.google.common.util.concurrent.Monitor; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static com.google.common.util.concurrent.Uninterruptibles.joinUninterruptibly; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class MonitorUnitTests { + + @Test + public void whenGaurdConditionIsTrue_IsSuccessful() { + Monitor monitor = new Monitor(); + boolean enteredInCriticalSection = false; + + Monitor.Guard gaurdCondition = monitor.newGuard(this::returnTrue); + + if(monitor.enterIf(gaurdCondition)){ + try{ + System.out.println("Entered in critical section"); + enteredInCriticalSection = true; + }finally { + monitor.leave(); + } + } + + Assert.assertTrue(enteredInCriticalSection); + + } + + @Test + public void whenGaurdConditionIsFalse_IsSuccessful() { + Monitor monitor = new Monitor(); + boolean enteredInCriticalSection = false; + + Monitor.Guard gaurdCondition = monitor.newGuard(this::returnFalse); + + if(monitor.enterIf(gaurdCondition)){ + try{ + System.out.println("Entered in critical section"); + enteredInCriticalSection = true; + }finally { + monitor.leave(); + } + } + + Assert.assertFalse(enteredInCriticalSection); + } + + private boolean returnTrue(){ + return true; + } + + private boolean returnFalse(){ + return false; + } +} From 361df0769448c4c761a1fef9b5b088ed8de29ec9 Mon Sep 17 00:00:00 2001 From: Nancy Bosecker Date: Tue, 28 Mar 2017 18:18:00 -0700 Subject: [PATCH 206/291] Added KeyDeserializer class and test code (#1523) * Solr w Apache SolrJ * Solr w Apache SolrJ * updated test names and moved add to @before method * create apache-solrj module, moved code from spring-data-solr * More examples for indexing,delete,and query for solrj * More examples for indexing,delete,and query for solrj * Jackson Map Serialize/Deserialize * Jackson Map Serialize/Deserialize * Jackson version update * keydeserializer code added * keydeserializer code added --- .../jackson/entities/ClassWithAMap.java | 24 +++++++++++++++++++ .../serialization/MyPairDeserializer.java | 18 ++++++++++++++ .../JacksonMapDeserializeTest.java | 10 +++++++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 jackson/src/main/java/com/baeldung/jackson/entities/ClassWithAMap.java create mode 100644 jackson/src/main/java/com/baeldung/jackson/serialization/MyPairDeserializer.java diff --git a/jackson/src/main/java/com/baeldung/jackson/entities/ClassWithAMap.java b/jackson/src/main/java/com/baeldung/jackson/entities/ClassWithAMap.java new file mode 100644 index 0000000000..54ebff8a56 --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/entities/ClassWithAMap.java @@ -0,0 +1,24 @@ +package com.baeldung.jackson.entities; + +import java.util.Map; + +import com.baeldung.jackson.serialization.MyPairDeserializer; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +public class ClassWithAMap { + + @JsonProperty("map") + @JsonDeserialize(keyUsing = MyPairDeserializer.class) + private final Map map; + + @JsonCreator + public ClassWithAMap(Map map) { + this.map = map; + } + + public Map getMap() { + return map; + } +} \ No newline at end of file diff --git a/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairDeserializer.java b/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairDeserializer.java new file mode 100644 index 0000000000..0aa6db98d0 --- /dev/null +++ b/jackson/src/main/java/com/baeldung/jackson/serialization/MyPairDeserializer.java @@ -0,0 +1,18 @@ +package com.baeldung.jackson.serialization; + +import java.io.IOException; + +import com.baeldung.jackson.entities.MyPair; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.KeyDeserializer; + +public class MyPairDeserializer extends KeyDeserializer { + + @Override + public MyPair deserializeKey(String key, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + + return new MyPair(key); + } +} \ No newline at end of file diff --git a/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java b/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java index 3be3981c9b..04eb89306b 100644 --- a/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/deserialization/JacksonMapDeserializeTest.java @@ -7,6 +7,7 @@ import java.util.Map; import org.junit.Assert; import org.junit.Test; +import com.baeldung.jackson.entities.ClassWithAMap; import com.baeldung.jackson.entities.MyPair; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.type.TypeReference; @@ -36,14 +37,21 @@ public class JacksonMapDeserializeTest { public void whenObjectStringMapDeserialize_thenCorrect() throws JsonParseException, JsonMappingException, IOException { - final String jsonInput = "{\"Abbott and Costello\" : \"Comedy\"}"; + final String jsonInput = "{\"Abbott and Costello\":\"Comedy\"}"; final ObjectMapper mapper = new ObjectMapper(); TypeReference> typeRef = new TypeReference>() { }; + map = mapper.readValue(jsonInput, typeRef); Assert.assertEquals("Comedy", map.get(new MyPair("Abbott", "Costello"))); + + ClassWithAMap classWithMap = mapper.readValue(jsonInput, + ClassWithAMap.class); + + Assert.assertEquals("Comedy", + classWithMap.getMap().get(new MyPair("Abbott", "Costello"))); } @Test From 1a7ccb824882d3df8c6353a4f4fc59ea791b7ff8 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Wed, 29 Mar 2017 04:14:32 +0200 Subject: [PATCH 207/291] Bael 756 (#1513) * BAEL-756 code for kotlin null-safety article * BAEL-756 fix typo * BAEL-756 increment version of Kotlin * BAEL-756 remove duplicate form pom --- kotlin/pom.xml | 7 +- .../com/baeldung/kotlin/NullSafetyTest.kt | 140 ++++++++++++++++++ 2 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt diff --git a/kotlin/pom.xml b/kotlin/pom.xml index f928cc4037..07fb6863d4 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -90,10 +90,9 @@ 4.12 - 1.0.6 - 1.0.6 - 1.0.6 - 1.0.6 + 1.1.1 + 1.1.1 + 1.1.1 \ No newline at end of file diff --git a/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt b/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt new file mode 100644 index 0000000000..2adc1032bc --- /dev/null +++ b/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt @@ -0,0 +1,140 @@ +package com.baeldung.kotlin + +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNull +import kotlin.test.assertTrue + + +class NullSafetyTest { + @Test + fun givenNonNullableField_whenAssignValueToIt_thenNotNeedToCheckAgainstNull() { + //given + var a: String = "value" + //a = null compilation error + + //then + assertEquals(a.length, 5) + } + + @Test + fun givenNullableField_whenReadValue_thenNeedToCheckAgainstNull() { + //given + var b: String? = "value" + b = null + + //when + if (b != null) { + + } else { + assertNull(b) + } + } + + @Test + fun givenComplexObject_whenUseSafeCall_thenShouldChainCallsResultingWithValue() { + //given + val p: Person? = Person(Country("ENG")) + + //when + val res = p?.country?.code + + //then + assertEquals(res, "ENG") + } + + @Test + fun givenComplexObject_whenUseSafeCall_thenShouldChainCallsResultingWithNull() { + //given + val p: Person? = Person(Country(null)) + + //when + val res = p?.country?.code + + //then + assertNull(res) + } + + @Test + fun givenCollectionOfObjects_whenUseLetOperator_thenShouldApplyActionOnlyOnNonNullValue() { + //given + val firstName = "Tom" + val secondName = "Michael" + val names: List = listOf(firstName, null, secondName) + + //when + var res = listOf() + for (item in names) { + item?.let { res = res.plus(it) } + } + + //then + assertEquals(2, res.size) + assertTrue { res.contains(firstName) } + assertTrue { res.contains(secondName) } + } + + @Test + fun givenNullableReference_whenUseElvisOperator_thenShouldReturnValueIfReferenceIsNotNull() { + //given + val value: String? = "name" + + //when + val res = value?.length ?: -1 + + //then + assertEquals(res, 4) + } + + @Test + fun givenNullableReference_whenUseElvisOperator_thenShouldReturnDefaultValueIfReferenceIsNull() { + //given + val value: String? = null + + //when + val res = value?.length ?: -1 + + //then + assertEquals(res, -1) + } + + @Test + fun givenNullableField_whenUsingDoubleExclamationMarkOperatorOnNull_thenThrowNPE() { + //given + var b: String? = "value" + b = null + + //when + assertFailsWith { + b!!.length + } + } + + @Test + fun givenNullableField_whenUsingDoubleExclamationMarkOperatorOnNotNull_thenReturnValue() { + //given + val b: String? = "value" + + //then + assertEquals(b!!.length, 5) + } + + @Test + fun givenNullableList_whenUseFilterNotNullMethod_thenRemoveALlNullValues() { + //given + val list: List = listOf("a", null, "b") + + //when + val res = list.filterNotNull() + + //then + assertEquals(res.size, 2) + assertTrue { res.contains("a") } + assertTrue { res.contains("b") } + } +} + +data class Person(val country: Country?) + +data class Country(val code: String?) \ No newline at end of file From e6d9dde9317f0429cd2f39f4f930b7496dede2a9 Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Wed, 29 Mar 2017 17:43:21 +0800 Subject: [PATCH 208/291] add a main-class variable on maven building and exclude IntegrationTests (#1530) * add a main-class variable on maven building and exclude IntegrationTests * hardcode spring-boot main class to Spring5Application --- spring-5/pom.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 6c52e6c8cc..f116ed73c0 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -70,6 +70,21 @@ org.springframework.boot spring-boot-maven-plugin + + com.baeldung.Spring5Application + JAR + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + From 6f75ad86a652d485776c8baae28c811f0481e4be Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Wed, 29 Mar 2017 13:41:37 +0200 Subject: [PATCH 209/291] Bael 756 (#1531) * BAEL-756 code for kotlin null-safety article * BAEL-756 fix typo * BAEL-756 increment version of Kotlin * BAEL-756 remove duplicate form pom * BAEL-756 add also and run example --- .../com/baeldung/kotlin/NullSafetyTest.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt b/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt index 2adc1032bc..0ecc74b6fb 100644 --- a/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt +++ b/kotlin/src/test/kotlin/com/baeldung/kotlin/NullSafetyTest.kt @@ -66,7 +66,27 @@ class NullSafetyTest { //when var res = listOf() for (item in names) { - item?.let { res = res.plus(it) } + item?.let { res = res.plus(it); it } + ?.also{it -> println("non nullable value: $it")} + } + + //then + assertEquals(2, res.size) + assertTrue { res.contains(firstName) } + assertTrue { res.contains(secondName) } + } + + @Test + fun fivenCollectionOfObject_whenUseRunOperator_thenExecuteActionOnNonNullValue(){ + //given + val firstName = "Tom" + val secondName = "Michael" + val names: List = listOf(firstName, null, secondName) + + //when + var res = listOf() + for (item in names) { + item?.run{res = res.plus(this)} } //then From b63ef448db503c66b11f99f65d6c6b9bc73a7454 Mon Sep 17 00:00:00 2001 From: Nancy Bosecker Date: Wed, 29 Mar 2017 08:42:38 -0700 Subject: [PATCH 210/291] removed explicit types from map instantiation (#1532) * Solr w Apache SolrJ * Solr w Apache SolrJ * updated test names and moved add to @before method * create apache-solrj module, moved code from spring-data-solr * More examples for indexing,delete,and query for solrj * More examples for indexing,delete,and query for solrj * Jackson Map Serialize/Deserialize * Jackson Map Serialize/Deserialize * Jackson version update * keydeserializer code added * keydeserializer code added * remove explicit types from map instantion --- .../jackson/serialization/JacksonMapSerializeTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java b/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java index 71ba698e8e..841b12ca03 100644 --- a/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java +++ b/jackson/src/test/java/com/baeldung/jackson/serialization/JacksonMapSerializeTest.java @@ -30,7 +30,7 @@ public class JacksonMapSerializeTest { public void whenSimpleMapSerialize_thenCorrect() throws JsonProcessingException { - Map map = new HashMap(); + Map map = new HashMap<>(); map.put("key", "value"); final ObjectMapper mapper = new ObjectMapper(); @@ -43,7 +43,7 @@ public class JacksonMapSerializeTest { public void whenCustomObjectStringMapSerialize_thenCorrect() throws JsonProcessingException { - map = new HashMap(); + map = new HashMap<>(); MyPair key = new MyPair("Abbott", "Costello"); map.put(key, "Comedy"); @@ -57,7 +57,7 @@ public class JacksonMapSerializeTest { public void whenCustomObjectObjectMapSerialize_thenCorrect() throws JsonProcessingException { - cmap = new HashMap(); + cmap = new HashMap<>(); mapKey = new MyPair("Abbott", "Costello"); mapValue = new MyPair("Comedy", "1940's"); cmap.put(mapKey, mapValue); From ea345fa246b290b7ee98fcc5e5016877b2bde7d2 Mon Sep 17 00:00:00 2001 From: gitterjim-I Date: Wed, 29 Mar 2017 22:18:20 +0100 Subject: [PATCH 211/291] Integrate forEach and stream changes to test, removing non-test class. (#1529) * article Bael-667 initial commit. * Switch to use logging framework for output. --- core-java/0.8260098203820962 | 0 .../FlattenNestedListTest.java | 82 +++++++++++-------- 2 files changed, 48 insertions(+), 34 deletions(-) create mode 100644 core-java/0.8260098203820962 diff --git a/core-java/0.8260098203820962 b/core-java/0.8260098203820962 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java index cf9334954b..fdf4934cb7 100644 --- a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -1,6 +1,8 @@ package com.baeldung.list.flattennestedlist; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; @@ -8,45 +10,60 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; public class FlattenNestedListTest { + private List> lol = new ArrayList<>(); + List ls1 = Arrays.asList("one:one", "one:two", "one:three"); + List ls2 = Arrays.asList("two:one", "two:two", "two:three"); + List ls3 = Arrays.asList("three:one", "three:two", "three:three"); - @Test - public void givenListOfListOfString_flattenNestedList1() { - // given - List ls1 = Arrays.asList("one:one", "one:two", "one:three"); - List ls2 = Arrays.asList("two:one", "two:two", "two:three"); - List ls3 = Arrays.asList("three:one", "three:two", "three:three"); + @Before + public void setup() { + lol.addAll(Arrays.asList(ls1, ls2, ls3)); + } - List> list = Arrays.asList(ls1, ls2, ls3); - - // when - List ls = flattenListOfListsImperatively(list); - - // then - assertNotNull(ls); - assertTrue(ls.size() == 9); - //TODO content assertion + @After + public void tearDown() { + lol = null; } @Test - public void givenListOfListOfString_flattenNestedList2() { - // given - List ls1 = Arrays.asList("one:one", "one:two", "one:three"); - List ls2 = Arrays.asList("two:one", "two:two", "two:three"); - List ls3 = Arrays.asList("three:one", "three:two", "three:three"); + public void givenString_flattenNestedList1() { + List ls = flattenListOfListsImperatively(lol); - List> list = Arrays.asList(ls1, ls2, ls3); - - // when - List ls = flattenListOfListsStream(list); - - // then assertNotNull(ls); assertTrue(ls.size() == 9); - //TODO content assertion + // assert content + assertEquals(ls.get(0), "one:one"); + assertEquals(ls.get(1), "one:two"); + assertEquals(ls.get(2), "one:three"); + assertEquals(ls.get(3), "two:one"); + assertEquals(ls.get(4), "two:two"); + assertEquals(ls.get(5), "two:three"); + assertEquals(ls.get(6), "three:one"); + assertEquals(ls.get(7), "three:two"); + assertEquals(ls.get(8), "three:three"); + } + + @Test + public void givenString_flattenNestedList2() { + List ls = flattenListOfListsStream(lol); + + assertNotNull(ls); + assertTrue(ls.size() == 9); + // assert content + assertEquals(ls.get(0), "one:one"); + assertEquals(ls.get(1), "one:two"); + assertEquals(ls.get(2), "one:three"); + assertEquals(ls.get(3), "two:one"); + assertEquals(ls.get(4), "two:two"); + assertEquals(ls.get(5), "two:three"); + assertEquals(ls.get(6), "three:one"); + assertEquals(ls.get(7), "three:two"); + assertEquals(ls.get(8), "three:three"); } public List flattenListOfListsImperatively(List> list) { @@ -56,9 +73,6 @@ public class FlattenNestedListTest { } public List flattenListOfListsStream(List> list) { - return list.stream() - .flatMap(Collection::stream) - .collect(Collectors.toList()); + return list.stream().flatMap(Collection::stream).collect(Collectors.toList()); } - } From 47dfe6b641733689028ce727837ebf834d8aacce Mon Sep 17 00:00:00 2001 From: "Eunice A. Obugyei" Date: Thu, 30 Mar 2017 07:28:32 +0000 Subject: [PATCH 212/291] Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] (#1224) * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Removed unnecessary comment * Added mockito-core dependency * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] Added Exception test cases * Applied baeldung formatter in Eclipse --- jee7/pom.xml | 1 + .../com/baeldung/jaxws/EmployeeService.java | 31 +++++ .../baeldung/jaxws/EmployeeServiceImpl.java | 48 ++++++++ .../config/EmployeeServicePublisher.java | 12 ++ .../exception/EmployeeAlreadyExists.java | 16 +++ .../jaxws/exception/EmployeeNotFound.java | 17 +++ .../com/baeldung/jaxws/model/Employee.java | 33 ++++++ .../jaxws/repository/EmployeeRepository.java | 22 ++++ .../repository/EmployeeRepositoryImpl.java | 68 +++++++++++ .../jaxws/EmployeeServiceLiveTest.java | 108 ++++++++++++++++++ 10 files changed, 356 insertions(+) create mode 100644 jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/model/Employee.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java create mode 100644 jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java create mode 100644 jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java diff --git a/jee7/pom.xml b/jee7/pom.xml index f275f56d58..3d5d7ccdc4 100644 --- a/jee7/pom.xml +++ b/jee7/pom.xml @@ -28,6 +28,7 @@ 3.6.0 2.6 + 1.10.19 diff --git a/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java b/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java new file mode 100644 index 0000000000..7544369992 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java @@ -0,0 +1,31 @@ +package com.baeldung.jaxws; + +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; + +import javax.jws.WebMethod; +import javax.jws.WebService; +import java.util.List; + +@WebService +public interface EmployeeService { + + @WebMethod + Employee getEmployee(int id) throws EmployeeNotFound; + + @WebMethod + Employee updateEmployee(int id, String name) throws EmployeeNotFound; + + @WebMethod + boolean deleteEmployee(int id) throws EmployeeNotFound; + + @WebMethod + Employee addEmployee(int id, String name) throws EmployeeAlreadyExists; + + @WebMethod + int countEmployees(); + + @WebMethod + List getAllEmployees(); +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java b/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java new file mode 100644 index 0000000000..35b84fe620 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java @@ -0,0 +1,48 @@ +package com.baeldung.jaxws; + +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; +import com.baeldung.jaxws.repository.EmployeeRepository; + +import javax.inject.Inject; +import javax.jws.WebMethod; +import javax.jws.WebService; +import java.util.List; + +@WebService(serviceName = "EmployeeService", endpointInterface = "com.baeldung.jaxws.EmployeeService") +public class EmployeeServiceImpl implements EmployeeService { + + @Inject + private EmployeeRepository employeeRepositoryImpl; + + @WebMethod + public Employee getEmployee(int id) throws EmployeeNotFound { + return employeeRepositoryImpl.getEmployee(id); + } + + @WebMethod + public Employee updateEmployee(int id, String name) throws EmployeeNotFound { + return employeeRepositoryImpl.updateEmployee(id, name); + } + + @WebMethod + public boolean deleteEmployee(int id) throws EmployeeNotFound { + return employeeRepositoryImpl.deleteEmployee(id); + } + + @WebMethod + public Employee addEmployee(int id, String name) throws EmployeeAlreadyExists { + return employeeRepositoryImpl.addEmployee(id, name); + } + + @WebMethod + public int countEmployees() { + return employeeRepositoryImpl.count(); + } + + @WebMethod + public List getAllEmployees() { + return employeeRepositoryImpl.getAllEmployees(); + } +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java b/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java new file mode 100644 index 0000000000..6d7acc88e0 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java @@ -0,0 +1,12 @@ +package com.baeldung.jaxws.config; + +import com.baeldung.jaxws.EmployeeServiceImpl; + +import javax.xml.ws.Endpoint; + +public class EmployeeServicePublisher { + + public static void main(String[] args) { + Endpoint.publish("http://localhost:8080/employeeservice", new EmployeeServiceImpl()); + } +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java new file mode 100644 index 0000000000..d7c9d0f2cc --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java @@ -0,0 +1,16 @@ +package com.baeldung.jaxws.exception; + +import javax.xml.ws.WebFault; +import java.io.Serializable; + +@WebFault +public class EmployeeAlreadyExists extends Exception implements Serializable { + + public EmployeeAlreadyExists() { + super("This employee already exist"); + } + + public EmployeeAlreadyExists(String str) { + super(str); + } +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java new file mode 100644 index 0000000000..667e3e0c72 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java @@ -0,0 +1,17 @@ +package com.baeldung.jaxws.exception; + +import javax.xml.ws.WebFault; +import java.io.Serializable; + +@WebFault +public class EmployeeNotFound extends Exception implements Serializable { + + public EmployeeNotFound() { + super("The specified employee does not exist"); + } + + public EmployeeNotFound(String str) { + super(str); + } + +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java new file mode 100644 index 0000000000..27d02354c0 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java @@ -0,0 +1,33 @@ +package com.baeldung.jaxws.model; + +import java.io.Serializable; + +public class Employee implements Serializable { + private int id; + private String firstName; + + public Employee() { + + } + + public Employee(int id, String firstName) { + this.id = id; + this.firstName = firstName; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java new file mode 100644 index 0000000000..3a8930ac04 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java @@ -0,0 +1,22 @@ +package com.baeldung.jaxws.repository; + +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; + +import java.util.List; + +public interface EmployeeRepository { + + List getAllEmployees(); + + Employee getEmployee(int id) throws EmployeeNotFound; + + Employee updateEmployee(int id, String name) throws EmployeeNotFound; + + boolean deleteEmployee(int id) throws EmployeeNotFound; + + Employee addEmployee(int id, String name) throws EmployeeAlreadyExists; + + int count(); +} diff --git a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java new file mode 100644 index 0000000000..0e728ae253 --- /dev/null +++ b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java @@ -0,0 +1,68 @@ +package com.baeldung.jaxws.repository; + +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; + +import java.util.ArrayList; +import java.util.List; + +public class EmployeeRepositoryImpl implements EmployeeRepository { + private List employeeList; + + public EmployeeRepositoryImpl() { + employeeList = new ArrayList<>(); + employeeList.add(new Employee(1, "Jane")); + employeeList.add(new Employee(2, "Jack")); + employeeList.add(new Employee(3, "George")); + } + + public List getAllEmployees() { + return employeeList; + } + + public Employee getEmployee(int id) throws EmployeeNotFound { + for (Employee emp : employeeList) { + if (emp.getId() == id) { + return emp; + } + } + throw new EmployeeNotFound(); + } + + public Employee updateEmployee(int id, String name) throws EmployeeNotFound { + for (Employee employee1 : employeeList) { + if (employee1.getId() == id) { + employee1.setId(id); + employee1.setFirstName(name); + return employee1; + } + } + throw new EmployeeNotFound(); + } + + public boolean deleteEmployee(int id) throws EmployeeNotFound { + for (Employee emp : employeeList) { + if (emp.getId() == id) { + employeeList.remove(emp); + return true; + } + } + throw new EmployeeNotFound(); + } + + public Employee addEmployee(int id, String name) throws EmployeeAlreadyExists { + for (Employee emp : employeeList) { + if (emp.getId() == id) { + throw new EmployeeAlreadyExists(); + } + } + Employee employee = new Employee(id, name); + employeeList.add(employee); + return employee; + } + + public int count() { + return employeeList.size(); + } +} diff --git a/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java new file mode 100644 index 0000000000..8907179b14 --- /dev/null +++ b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java @@ -0,0 +1,108 @@ +package com.baeldung.jaxws; + +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; +import com.baeldung.jaxws.repository.EmployeeRepository; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(Arquillian.class) +public class EmployeeServiceLiveTest { + + private static final String APP_NAME = "jee7"; + private static final String WSDL_PATH = "EmployeeService?wsdl"; + private static QName SERVICE_NAME = new QName("http://jaxws.baeldung.com/", "EmployeeService"); + private static URL wsdlUrl; + + @ArquillianResource + private URL deploymentUrl; + + private EmployeeService employeeServiceProxy; + + @Deployment(testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap.create(WebArchive.class, APP_NAME + ".war").addPackage(EmployeeService.class.getPackage()).addPackage(Employee.class.getPackage()).addPackage(EmployeeNotFound.class.getPackage()).addPackage(EmployeeRepository.class.getPackage()) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Before + public void setUp() { + try { + wsdlUrl = new URL(deploymentUrl, WSDL_PATH); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + + Service service = Service.create(wsdlUrl, SERVICE_NAME); + employeeServiceProxy = service.getPort(EmployeeService.class); + } + + @Test + public void givenGetAllEmployees_thenCorrectNumberOfEmployeesReturned() { + int employeeCount = employeeServiceProxy.countEmployees(); + List employeeList = employeeServiceProxy.getAllEmployees(); + assertEquals(employeeList.size(), employeeCount); + } + + @Test + public void givenEmployeeId_whenEmployeeExists_thenCorrectEmployeeReturned() throws EmployeeNotFound { + Employee employee = employeeServiceProxy.getEmployee(2); + assertEquals(employee.getFirstName(), "Jack"); + } + + @Test(expected = EmployeeNotFound.class) + public void givenEmployeeId_whenEmployeeNotExists_thenEmployeeNotFoundExceptionReturned() throws EmployeeNotFound { + employeeServiceProxy.getEmployee(20); + } + + @Test + public void givenAddEmployee_whenEmployeeDoesntAlreadyExist_thenEmployeeCountIncreased() throws EmployeeAlreadyExists { + int employeeCount = employeeServiceProxy.countEmployees(); + employeeServiceProxy.addEmployee(4, "Anna"); + assertEquals(employeeServiceProxy.countEmployees(), employeeCount + 1); + } + + @Test(expected = EmployeeAlreadyExists.class) + public void givenAddEmployee_whenEmployeeAlreadyExist_thenEmployeeAlreadyExistsExceptionReturned() throws EmployeeAlreadyExists { + employeeServiceProxy.addEmployee(1, "Anna"); + } + + @Test + public void givenUpdateEmployee_whenEmployeeExists_thenUpdatedEmployeeReturned() throws EmployeeNotFound { + Employee updated = employeeServiceProxy.updateEmployee(1, "Joan"); + assertEquals(updated.getFirstName(), "Joan"); + } + + @Test(expected = EmployeeNotFound.class) + public void givenUpdateEmployee_whenEmployeeNotExists_thenUpdatedEmployeeReturned() throws EmployeeNotFound { + employeeServiceProxy.updateEmployee(20, "Joan"); + } + + @Test + public void givenDeleteEmployee_whenEmployeeExists_thenCorrectStatusReturned() throws EmployeeNotFound { + boolean deleteEmployee = employeeServiceProxy.deleteEmployee(3); + assertEquals(deleteEmployee, true); + } + + @Test(expected = EmployeeNotFound.class) + public void givenDeleteEmployee_whenEmployeeNotExists_thenEmployeeNotFoundExceptionReturned() throws EmployeeNotFound { + employeeServiceProxy.deleteEmployee(20); + } + +} From ec089be605ffcc7e699ef9d35630a824fd436c1e Mon Sep 17 00:00:00 2001 From: Sunil Mogadati Date: Thu, 30 Mar 2017 02:54:26 -0600 Subject: [PATCH 213/291] BAEL-611: Minor formatting changes (#1534) * Add NDC and JBoss Logging to the demo application * NDC for Log4j, Log4j2 and JBoss Logging * Simplify NDC example by making it a single operation instead of two * Make NDC example as RestController, Use JBoss Logging only as a logging bridge * Fix merge conflicts in pull request - log-mdc pom.xml updated * BAEL-445 Update to Spring security SpEL example * BAEL-445: Change tabs to spaces in the updated code * BAEL-245: Add Enum Serialization exmaple * BAEL-245: Remove the folder jackson/src/test/java/com/baeldung/jackson/dtos/withEnum as the example is not used anymore * Add more enum serialization examples to align with previous example and prevent build fail * BAEL-611: Minor formatting changes * BAEL-611: Update Test case method names --- jee7/pom.xml | 1 - .../com/baeldung/jaxws/EmployeeService.java | 9 ++-- .../baeldung/jaxws/EmployeeServiceImpl.java | 11 ++--- .../config/EmployeeServicePublisher.java | 4 +- .../exception/EmployeeAlreadyExists.java | 7 +++- .../com/baeldung/jaxws/model/Employee.java | 1 + .../jaxws/repository/EmployeeRepository.java | 4 +- .../repository/EmployeeRepositoryImpl.java | 6 +-- .../jaxws/EmployeeServiceLiveTest.java | 42 ++++++++++--------- 9 files changed, 46 insertions(+), 39 deletions(-) diff --git a/jee7/pom.xml b/jee7/pom.xml index 3d5d7ccdc4..f275f56d58 100644 --- a/jee7/pom.xml +++ b/jee7/pom.xml @@ -28,7 +28,6 @@ 3.6.0 2.6 - 1.10.19 diff --git a/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java b/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java index 7544369992..9735607da6 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java +++ b/jee7/src/main/java/com/baeldung/jaxws/EmployeeService.java @@ -1,13 +1,14 @@ package com.baeldung.jaxws; +import java.util.List; + +import javax.jws.WebMethod; +import javax.jws.WebService; + import com.baeldung.jaxws.exception.EmployeeAlreadyExists; import com.baeldung.jaxws.exception.EmployeeNotFound; import com.baeldung.jaxws.model.Employee; -import javax.jws.WebMethod; -import javax.jws.WebService; -import java.util.List; - @WebService public interface EmployeeService { diff --git a/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java b/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java index 35b84fe620..c1c9cd4385 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java +++ b/jee7/src/main/java/com/baeldung/jaxws/EmployeeServiceImpl.java @@ -1,15 +1,16 @@ package com.baeldung.jaxws; +import java.util.List; + +import javax.inject.Inject; +import javax.jws.WebMethod; +import javax.jws.WebService; + import com.baeldung.jaxws.exception.EmployeeAlreadyExists; import com.baeldung.jaxws.exception.EmployeeNotFound; import com.baeldung.jaxws.model.Employee; import com.baeldung.jaxws.repository.EmployeeRepository; -import javax.inject.Inject; -import javax.jws.WebMethod; -import javax.jws.WebService; -import java.util.List; - @WebService(serviceName = "EmployeeService", endpointInterface = "com.baeldung.jaxws.EmployeeService") public class EmployeeServiceImpl implements EmployeeService { diff --git a/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java b/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java index 6d7acc88e0..ac3b049320 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java +++ b/jee7/src/main/java/com/baeldung/jaxws/config/EmployeeServicePublisher.java @@ -1,9 +1,9 @@ package com.baeldung.jaxws.config; -import com.baeldung.jaxws.EmployeeServiceImpl; - import javax.xml.ws.Endpoint; +import com.baeldung.jaxws.EmployeeServiceImpl; + public class EmployeeServicePublisher { public static void main(String[] args) { diff --git a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java index d7c9d0f2cc..4842fbf84c 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java +++ b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java @@ -1,13 +1,16 @@ package com.baeldung.jaxws.exception; -import javax.xml.ws.WebFault; import java.io.Serializable; +import javax.xml.ws.WebFault; + @WebFault public class EmployeeAlreadyExists extends Exception implements Serializable { + private static final long serialVersionUID = 1L; + public EmployeeAlreadyExists() { - super("This employee already exist"); + super("This employee already exists"); } public EmployeeAlreadyExists(String str) { diff --git a/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java index 27d02354c0..5b1673c1e4 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java +++ b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java @@ -3,6 +3,7 @@ package com.baeldung.jaxws.model; import java.io.Serializable; public class Employee implements Serializable { + private static final long serialVersionUID = 1L; private int id; private String firstName; diff --git a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java index 3a8930ac04..0d5dec0462 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java +++ b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepository.java @@ -1,11 +1,11 @@ package com.baeldung.jaxws.repository; +import java.util.List; + import com.baeldung.jaxws.exception.EmployeeAlreadyExists; import com.baeldung.jaxws.exception.EmployeeNotFound; import com.baeldung.jaxws.model.Employee; -import java.util.List; - public interface EmployeeRepository { List getAllEmployees(); diff --git a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java index 0e728ae253..f67509fff5 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java +++ b/jee7/src/main/java/com/baeldung/jaxws/repository/EmployeeRepositoryImpl.java @@ -1,12 +1,12 @@ package com.baeldung.jaxws.repository; +import java.util.ArrayList; +import java.util.List; + import com.baeldung.jaxws.exception.EmployeeAlreadyExists; import com.baeldung.jaxws.exception.EmployeeNotFound; import com.baeldung.jaxws.model.Employee; -import java.util.ArrayList; -import java.util.List; - public class EmployeeRepositoryImpl implements EmployeeRepository { private List employeeList; diff --git a/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java index 8907179b14..5311b3c5fe 100644 --- a/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java +++ b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java @@ -1,9 +1,14 @@ package com.baeldung.jaxws; -import com.baeldung.jaxws.exception.EmployeeAlreadyExists; -import com.baeldung.jaxws.exception.EmployeeNotFound; -import com.baeldung.jaxws.model.Employee; -import com.baeldung.jaxws.repository.EmployeeRepository; +import static org.junit.Assert.assertEquals; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; @@ -14,13 +19,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import javax.xml.namespace.QName; -import javax.xml.ws.Service; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; - -import static org.junit.Assert.assertEquals; +import com.baeldung.jaxws.exception.EmployeeAlreadyExists; +import com.baeldung.jaxws.exception.EmployeeNotFound; +import com.baeldung.jaxws.model.Employee; +import com.baeldung.jaxws.repository.EmployeeRepository; @RunWith(Arquillian.class) public class EmployeeServiceLiveTest { @@ -54,54 +56,54 @@ public class EmployeeServiceLiveTest { } @Test - public void givenGetAllEmployees_thenCorrectNumberOfEmployeesReturned() { + public void givenEmployees_whenGetCount_thenCorrectNumberOfEmployeesReturned() { int employeeCount = employeeServiceProxy.countEmployees(); List employeeList = employeeServiceProxy.getAllEmployees(); assertEquals(employeeList.size(), employeeCount); } @Test - public void givenEmployeeId_whenEmployeeExists_thenCorrectEmployeeReturned() throws EmployeeNotFound { + public void givenEmployees_whenGetAvailableEmployee_thenCorrectEmployeeReturned() throws EmployeeNotFound { Employee employee = employeeServiceProxy.getEmployee(2); assertEquals(employee.getFirstName(), "Jack"); } @Test(expected = EmployeeNotFound.class) - public void givenEmployeeId_whenEmployeeNotExists_thenEmployeeNotFoundExceptionReturned() throws EmployeeNotFound { + public void givenEmployees_whenGetNonAvailableEmployee_thenEmployeeNotFoundException() throws EmployeeNotFound { employeeServiceProxy.getEmployee(20); } @Test - public void givenAddEmployee_whenEmployeeDoesntAlreadyExist_thenEmployeeCountIncreased() throws EmployeeAlreadyExists { + public void givenEmployees_whenAddNewEmployee_thenEmployeeCountIncreased() throws EmployeeAlreadyExists { int employeeCount = employeeServiceProxy.countEmployees(); employeeServiceProxy.addEmployee(4, "Anna"); assertEquals(employeeServiceProxy.countEmployees(), employeeCount + 1); } @Test(expected = EmployeeAlreadyExists.class) - public void givenAddEmployee_whenEmployeeAlreadyExist_thenEmployeeAlreadyExistsExceptionReturned() throws EmployeeAlreadyExists { + public void givenEmployees_whenAddAlreadyExistingEmployee_thenEmployeeAlreadyExistsException() throws EmployeeAlreadyExists { employeeServiceProxy.addEmployee(1, "Anna"); } @Test - public void givenUpdateEmployee_whenEmployeeExists_thenUpdatedEmployeeReturned() throws EmployeeNotFound { + public void givenEmployees_whenUpdateExistingEmployee_thenUpdatedEmployeeReturned() throws EmployeeNotFound { Employee updated = employeeServiceProxy.updateEmployee(1, "Joan"); assertEquals(updated.getFirstName(), "Joan"); } @Test(expected = EmployeeNotFound.class) - public void givenUpdateEmployee_whenEmployeeNotExists_thenUpdatedEmployeeReturned() throws EmployeeNotFound { + public void givenEmployees_whenUpdateNonExistingEmployee_thenEmployeeNotFoundException() throws EmployeeNotFound { employeeServiceProxy.updateEmployee(20, "Joan"); } @Test - public void givenDeleteEmployee_whenEmployeeExists_thenCorrectStatusReturned() throws EmployeeNotFound { + public void givenEmployees_whenDeleteExistingEmployee_thenSuccessReturned() throws EmployeeNotFound { boolean deleteEmployee = employeeServiceProxy.deleteEmployee(3); assertEquals(deleteEmployee, true); } @Test(expected = EmployeeNotFound.class) - public void givenDeleteEmployee_whenEmployeeNotExists_thenEmployeeNotFoundExceptionReturned() throws EmployeeNotFound { + public void givenEmployee_whenDeleteNonExistingEmployee_thenEmployeeNotFoundException() throws EmployeeNotFound { employeeServiceProxy.deleteEmployee(20); } From e28dfe6a4a7fa86535ec9af97bd4d6d17c4e9d7f Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Thu, 30 Mar 2017 13:52:40 +0200 Subject: [PATCH 214/291] modify ratings controller (#1536) * upgrade to spring boot 1.5.2 * add full update to REST API * modify ratings controller --- .../bootstrap/svcrating/rating/RatingController.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java index cbfeda49c0..91966034f6 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java @@ -2,6 +2,7 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; import java.util.List; import java.util.Map; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; @@ -23,11 +24,9 @@ public class RatingController { private RatingService ratingService; @GetMapping - public List findRatingsByBookId(@RequestParam(required = false, defaultValue = "0") Long bookId) { - if (bookId.equals(0L)) { - return ratingService.findAllRatings(); - } - return ratingService.findRatingsByBookId(bookId); + public List findRatingsByBookId(@RequestParam(required = false) Optional bookId) { + return bookId.map(ratingService::findRatingsByBookId) + .orElseGet(ratingService::findAllRatings); } @PostMapping From ce589cc7b5b78edd80ff3b818ed53dd2af5bb98c Mon Sep 17 00:00:00 2001 From: Devendra Tiwari Date: Thu, 30 Mar 2017 23:51:17 +0530 Subject: [PATCH 215/291] Corrected Indentation using formatter. (#1541) --- .../tutorial/AtomicLongMapTutorials.java | 15 ++-- .../guava/tutorial/ComparatorsExamples.java | 6 +- .../guava/tutorial/ConcatStreams.java | 4 +- .../tutorial/InternerBuilderExample.java | 12 +-- .../guava/tutorial/MonitorExample.java | 4 +- .../guava/tutorial/MoreCollectorsExample.java | 7 +- .../guava/tutorial/StreamsUtility.java | 13 ++-- guava21/src/test/java/AtomicLongMapTests.java | 46 +++++------- .../src/test/java/ComparatorsUnitTests.java | 15 ++-- guava21/src/test/java/GauavaStreamsTests.java | 75 ++++++++++--------- .../src/test/java/InternBuilderUnitTests.java | 9 +-- guava21/src/test/java/MonitorUnitTests.java | 24 ++---- .../test/java/MoreCollectorsUnitTests.java | 24 +++--- guava21/src/test/java/StreamUtility.java | 10 +-- 14 files changed, 119 insertions(+), 145 deletions(-) diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java b/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java index 69ad04ad9c..79ce02b7f0 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/AtomicLongMapTutorials.java @@ -6,19 +6,18 @@ public class AtomicLongMapTutorials { private AtomicLongMap atomicLongMap; - public AtomicLongMapTutorials(){ + public AtomicLongMapTutorials() { atomicLongMap = AtomicLongMap.create(); } - - public void addKeys(){ - atomicLongMap.addAndGet("apple",250); - atomicLongMap.addAndGet("bat",350); - atomicLongMap.addAndGet("cat",450); - atomicLongMap.addAndGet("dog",550); + public void addKeys() { + atomicLongMap.addAndGet("apple", 250); + atomicLongMap.addAndGet("bat", 350); + atomicLongMap.addAndGet("cat", 450); + atomicLongMap.addAndGet("dog", 550); } - public static void main(String[] args){ + public static void main(String[] args) { AtomicLongMapTutorials atomicLongMapTutorials = new AtomicLongMapTutorials(); atomicLongMapTutorials.addKeys(); diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java b/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java index 6eb5c7f5ba..abb4c51e8f 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/ComparatorsExamples.java @@ -8,12 +8,10 @@ import java.util.List; public class ComparatorsExamples { - public static void main(String[] args){ + public static void main(String[] args) { - List integers = Arrays.asList(1,2,3,4,4,6,7,8,9,10); - //This will return true + List integers = Arrays.asList(1, 2, 3, 4, 4, 6, 7, 8, 9, 10); boolean isInAscendingOrder = Comparators.isInOrder(integers, new AscedingOrderComparator()); - System.out.println(isInAscendingOrder); } diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java b/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java index ab95b85751..0304d48fbc 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/ConcatStreams.java @@ -5,7 +5,7 @@ import com.google.common.collect.Streams; import java.util.stream.Stream; public class ConcatStreams { - public static Stream concatStreams(Stream stream1, Stream stream2, Stream stream3){ - return Streams.concat(stream1,stream2,stream3); + public static Stream concatStreams(Stream stream1, Stream stream2, Stream stream3) { + return Streams.concat(stream1, stream2, stream3); } } diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java index 6b935ba2a8..5c85e684d5 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/InternerBuilderExample.java @@ -3,16 +3,12 @@ package com.baeldung.guava.tutorial; import com.google.common.collect.Interner; import com.google.common.collect.Interners; -import static com.google.common.collect.Interners.newBuilder; - public class InternerBuilderExample { - public static void main(String[] args){ - Interner interners = Interners.newBuilder() - .concurrencyLevel(2) - .strong() - .build(); - + public static void main(String[] args) { + Interner interners = Interners. newBuilder() + .concurrencyLevel(2) + .strong(). build(); } diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java index 2f316c293e..78bcbe3d49 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/MonitorExample.java @@ -4,7 +4,6 @@ import com.google.common.util.concurrent.Monitor; import java.util.ArrayList; import java.util.List; -import java.util.function.BooleanSupplier; public class MonitorExample { private List students = new ArrayList(); @@ -12,7 +11,6 @@ public class MonitorExample { private Monitor monitor = new Monitor(); - public void addToCourse(String item) throws InterruptedException { Monitor.Guard studentsBelowCapacity = monitor.newGuard(this::isStudentsCapacityUptoLimit); monitor.enterWhen(studentsBelowCapacity); @@ -23,7 +21,7 @@ public class MonitorExample { } } - public Boolean isStudentsCapacityUptoLimit(){ + public Boolean isStudentsCapacityUptoLimit() { return students.size() > MAX_SIZE; } } diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java b/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java index 6cf4b6b0ac..2b3bd7cdc4 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/MoreCollectorsExample.java @@ -10,8 +10,9 @@ public class MoreCollectorsExample { public static void main(String[] args) { List numbers = Arrays.asList(1); - Optional number = numbers.stream() - .map(e -> e * 2) - .collect(MoreCollectors.toOptional()); + Optional number = numbers + .stream() + .map(e -> e * 2) + .collect(MoreCollectors.toOptional()); } } diff --git a/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java b/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java index 4ec3b44ef4..b15f61afd5 100644 --- a/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java +++ b/guava21/src/main/java/com/baeldung/guava/tutorial/StreamsUtility.java @@ -10,9 +10,9 @@ import java.util.stream.Stream; public class StreamsUtility { - public static void main(String[] args){ + public static void main(String[] args) { - List numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20); + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); //Using Collection Stream streamFromCollection = Streams.stream(numbers); //Using Iterator @@ -28,15 +28,12 @@ public class StreamsUtility { //Using OptionalDouble to DoubleStream DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0)); - Stream concatenatedStreams = Streams.concat(streamFromCollection,streamFromIterable,streamFromIterator); + Stream concatenatedStreams = Streams.concat(streamFromCollection, streamFromIterable, streamFromIterator); - List integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10); + List integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); //This will return 10 Optional lastItem = Streams.findLast(integers.stream()); - Streams.zip( - Stream.of("candy", "chocolate", "bar"), - Stream.of("$1", "$2","$3"), - (arg1, arg2) -> arg1 + ":" + arg2); + Streams.zip(Stream.of("candy", "chocolate", "bar"), Stream.of("$1", "$2", "$3"), (arg1, arg2) -> arg1 + ":" + arg2); } } diff --git a/guava21/src/test/java/AtomicLongMapTests.java b/guava21/src/test/java/AtomicLongMapTests.java index aad72907de..6bde997e8d 100644 --- a/guava21/src/test/java/AtomicLongMapTests.java +++ b/guava21/src/test/java/AtomicLongMapTests.java @@ -1,5 +1,4 @@ import com.google.common.util.concurrent.AtomicLongMap; -import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -12,35 +11,28 @@ public class AtomicLongMapTests { AtomicLongMap courses = AtomicLongMap.create(); - public void setUp(){ + public void setUp() { courses.put(SPRING_COURSE_KEY, 1056); courses.put(HIBERNATE_COURSE_KEY, 259); courses.put(GUAVA_COURSE_KEY, 78); } + @Test + public void accumulateAndGet_withLongBinaryOperator_thenSuccessful() { + long noOfStudents = 56; + long oldValue = courses.get(SPRING_COURSE_KEY); -@Test -public void accumulateAndGet_withLongBinaryOperator_thenSuccessful(){ - long noOfStudents = 56; - long oldValue = courses.get(SPRING_COURSE_KEY); + long totalNotesRequired = courses.accumulateAndGet("Guava", noOfStudents, (x, y) -> (x * y)); - long totalNotesRequired = courses.accumulateAndGet( - "Guava", - noOfStudents, - (x,y) -> (x * y)); - - assertEquals(totalNotesRequired, oldValue * noOfStudents ); -} + assertEquals(totalNotesRequired, oldValue * noOfStudents); + } @Test - public void getAndAccumulate_withLongBinaryOperator_thenSuccessful(){ + public void getAndAccumulate_withLongBinaryOperator_thenSuccessful() { long noOfStudents = 56; long beforeUpdate = courses.get(SPRING_COURSE_KEY); - long onUpdate = courses.accumulateAndGet("Guava", - noOfStudents, - (x,y) -> (x * y) - ); + long onUpdate = courses.accumulateAndGet("Guava", noOfStudents, (x, y) -> (x * y)); long afterUpdate = courses.get(SPRING_COURSE_KEY); @@ -48,17 +40,15 @@ public void accumulateAndGet_withLongBinaryOperator_thenSuccessful(){ assertEquals(afterUpdate, beforeUpdate * noOfStudents); } -@Test -public void updateAndGet_withLongUnaryOperator_thenSuccessful(){ - long beforeUpdate = courses.get(SPRING_COURSE_KEY); + @Test + public void updateAndGet_withLongUnaryOperator_thenSuccessful() { + long beforeUpdate = courses.get(SPRING_COURSE_KEY); - long onUpdate = courses.updateAndGet( - "Guava", - (x) -> (x/2)); + long onUpdate = courses.updateAndGet("Guava", (x) -> (x / 2)); - long afterUpdate = courses.get(SPRING_COURSE_KEY); + long afterUpdate = courses.get(SPRING_COURSE_KEY); - assertEquals(onUpdate, afterUpdate); - assertEquals(afterUpdate, beforeUpdate/2); -} + assertEquals(onUpdate, afterUpdate); + assertEquals(afterUpdate, beforeUpdate / 2); + } } diff --git a/guava21/src/test/java/ComparatorsUnitTests.java b/guava21/src/test/java/ComparatorsUnitTests.java index f196c41a1b..8aaae1e14e 100644 --- a/guava21/src/test/java/ComparatorsUnitTests.java +++ b/guava21/src/test/java/ComparatorsUnitTests.java @@ -2,7 +2,9 @@ import com.google.common.collect.Comparators; import org.junit.Assert; import org.junit.Test; -import java.util.*; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; import java.util.function.Function; import java.util.function.ToDoubleFunction; import java.util.function.ToIntFunction; @@ -11,9 +13,9 @@ import java.util.function.ToLongFunction; public class ComparatorsUnitTests { @Test - public void isInOrderTest(){ + public void isInOrderTest() { - List numbers = Arrays.asList(1,2,3,4,4,6,7,8,9,10); + List numbers = Arrays.asList(1, 2, 3, 4, 4, 6, 7, 8, 9, 10); boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator()); @@ -21,17 +23,16 @@ public class ComparatorsUnitTests { } @Test - public void isInStrictOrderTest(){ + public void isInStrictOrderTest() { - List numbers = Arrays.asList(1,2,3,4,3,6,7,8,9,10); + List numbers = Arrays.asList(1, 2, 3, 4, 3, 6, 7, 8, 9, 10); boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator()); Assert.assertFalse(isInAscendingOrder); } - - private class AscendingOrderComparator implements Comparator{ + private class AscendingOrderComparator implements Comparator { @Override public int compare(Integer o1, Integer o2) { diff --git a/guava21/src/test/java/GauavaStreamsTests.java b/guava21/src/test/java/GauavaStreamsTests.java index 09e3e29b47..1482d685cf 100644 --- a/guava21/src/test/java/GauavaStreamsTests.java +++ b/guava21/src/test/java/GauavaStreamsTests.java @@ -14,13 +14,12 @@ public class GauavaStreamsTests { List numbers; @Before - public void setUp(){ - numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20); + public void setUp() { + numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); } - @Test - public void createStreamsWithCollection(){ + public void createStreamsWithCollection() { //Deprecated API to create stream from collection Stream streamFromCollection = Streams.stream(numbers); @@ -29,7 +28,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithIterable(){ + public void createStreamsWithIterable() { Iterable numbersIterable = (Iterable) numbers; Stream streamFromIterable = Streams.stream(numbersIterable); @@ -39,7 +38,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithIterator(){ + public void createStreamsWithIterator() { Iterator numbersIterator = numbers.iterator(); Stream streamFromIterator = Streams.stream(numbersIterator); @@ -49,7 +48,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithOptional(){ + public void createStreamsWithOptional() { Stream streamFromOptional = Streams.stream(Optional.of(1)); @@ -58,7 +57,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithOptionalLong(){ + public void createStreamsWithOptionalLong() { LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1)); @@ -67,7 +66,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithOptionalInt(){ + public void createStreamsWithOptionalInt() { IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1)); @@ -76,7 +75,7 @@ public class GauavaStreamsTests { } @Test - public void createStreamsWithOptionalDouble(){ + public void createStreamsWithOptionalDouble() { DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0)); @@ -86,41 +85,44 @@ public class GauavaStreamsTests { } @Test - public void concatStreamsOfSameType(){ - Stream oddNumbers = Arrays.asList(1,3,5,7,9,11,13,15,17,19).stream(); - Stream evenNumbers = Arrays.asList(2,4,6,8,10,12,14,16,18,20).stream(); + public void concatStreamsOfSameType() { + Stream oddNumbers = Arrays + .asList(1, 3, 5, 7, 9, 11, 13, 15, 17, 19) + .stream(); + Stream evenNumbers = Arrays + .asList(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) + .stream(); - Stream combinedStreams = Streams.concat(oddNumbers,evenNumbers); + Stream combinedStreams = Streams.concat(oddNumbers, evenNumbers); //Assert.assertNotNull(combinedStreams); StreamUtility.assertStreamEquals(combinedStreams, Stream.concat(oddNumbers, evenNumbers)); } @Test - public void concatStreamsOfTypeLongStream(){ - LongStream firstTwenty = LongStream.range(1,20); - LongStream nextTwenty = LongStream.range(21,40); + public void concatStreamsOfTypeLongStream() { + LongStream firstTwenty = LongStream.range(1, 20); + LongStream nextTwenty = LongStream.range(21, 40); - LongStream combinedStreams = Streams.concat(firstTwenty,nextTwenty); + LongStream combinedStreams = Streams.concat(firstTwenty, nextTwenty); Assert.assertNotNull(combinedStreams); StreamUtility.assertStreamEquals(combinedStreams, LongStream.concat(firstTwenty, nextTwenty)); } @Test - public void concatStreamsOfTypeIntStream(){ - IntStream firstTwenty = IntStream.range(1,20); - IntStream nextTwenty = IntStream.range(21,40); + public void concatStreamsOfTypeIntStream() { + IntStream firstTwenty = IntStream.range(1, 20); + IntStream nextTwenty = IntStream.range(21, 40); - IntStream combinedStreams = Streams.concat(firstTwenty,nextTwenty); + IntStream combinedStreams = Streams.concat(firstTwenty, nextTwenty); Assert.assertNotNull(combinedStreams); StreamUtility.assertStreamEquals(combinedStreams, IntStream.concat(firstTwenty, nextTwenty)); } - @Test - public void findLastOfStream(){ + public void findLastOfStream() { Optional lastElement = Streams.findLast(numbers.stream()); Assert.assertNotNull(lastElement.get()); @@ -128,28 +130,29 @@ public class GauavaStreamsTests { } @Test - public void mapWithIndexTest(){ - Stream stringSream = Stream.of("a","b","c"); + public void mapWithIndexTest() { + Stream stringSream = Stream.of("a", "b", "c"); - Stream mappedStream = Streams.mapWithIndex(stringSream,(str,index) -> str +":"+ index); + Stream mappedStream = Streams.mapWithIndex(stringSream, (str, index) -> str + ":" + index); //Assert.assertNotNull(mappedStream); - Assert.assertEquals(mappedStream.findFirst().get(), "a:0"); + Assert.assertEquals(mappedStream + .findFirst() + .get(), "a:0"); } @Test - public void streamsZipTest(){ - Stream stringSream = Stream.of("a","b","c"); - Stream intStream = Stream.of(1,2,3); - Stream mappedStream = Streams.zip(stringSream,intStream, (str,index) -> str +":"+ index); + public void streamsZipTest() { + Stream stringSream = Stream.of("a", "b", "c"); + Stream intStream = Stream.of(1, 2, 3); + Stream mappedStream = Streams.zip(stringSream, intStream, (str, index) -> str + ":" + index); //Assert.assertNotNull(mappedStream); - Assert.assertEquals(mappedStream.findFirst().get(), "a:1"); + Assert.assertEquals(mappedStream + .findFirst() + .get(), "a:1"); } - - - } diff --git a/guava21/src/test/java/InternBuilderUnitTests.java b/guava21/src/test/java/InternBuilderUnitTests.java index 513b44f249..b569b59978 100644 --- a/guava21/src/test/java/InternBuilderUnitTests.java +++ b/guava21/src/test/java/InternBuilderUnitTests.java @@ -6,12 +6,11 @@ import org.junit.Test; public class InternBuilderUnitTests { @Test - public void interBuilderTest(){ + public void interBuilderTest() { - Interner interners = Interners.newBuilder() - .concurrencyLevel(2) - .strong() - .build(); + Interner interners = Interners. newBuilder() + .concurrencyLevel(2) + .strong(). build(); Assert.assertNotNull(interners); } diff --git a/guava21/src/test/java/MonitorUnitTests.java b/guava21/src/test/java/MonitorUnitTests.java index 6427072db9..7b52c48d8f 100644 --- a/guava21/src/test/java/MonitorUnitTests.java +++ b/guava21/src/test/java/MonitorUnitTests.java @@ -2,14 +2,6 @@ import com.google.common.util.concurrent.Monitor; import org.junit.Assert; import org.junit.Test; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import static com.google.common.util.concurrent.Uninterruptibles.joinUninterruptibly; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - public class MonitorUnitTests { @Test @@ -19,11 +11,11 @@ public class MonitorUnitTests { Monitor.Guard gaurdCondition = monitor.newGuard(this::returnTrue); - if(monitor.enterIf(gaurdCondition)){ - try{ + if (monitor.enterIf(gaurdCondition)) { + try { System.out.println("Entered in critical section"); enteredInCriticalSection = true; - }finally { + } finally { monitor.leave(); } } @@ -39,11 +31,11 @@ public class MonitorUnitTests { Monitor.Guard gaurdCondition = monitor.newGuard(this::returnFalse); - if(monitor.enterIf(gaurdCondition)){ - try{ + if (monitor.enterIf(gaurdCondition)) { + try { System.out.println("Entered in critical section"); enteredInCriticalSection = true; - }finally { + } finally { monitor.leave(); } } @@ -51,11 +43,11 @@ public class MonitorUnitTests { Assert.assertFalse(enteredInCriticalSection); } - private boolean returnTrue(){ + private boolean returnTrue() { return true; } - private boolean returnFalse(){ + private boolean returnFalse() { return false; } } diff --git a/guava21/src/test/java/MoreCollectorsUnitTests.java b/guava21/src/test/java/MoreCollectorsUnitTests.java index 956331e25f..a205337450 100644 --- a/guava21/src/test/java/MoreCollectorsUnitTests.java +++ b/guava21/src/test/java/MoreCollectorsUnitTests.java @@ -9,28 +9,28 @@ import java.util.Optional; public class MoreCollectorsUnitTests { @Test - public void toOptionalTest(){ + public void toOptionalTest() { List numbers = Arrays.asList(1); - Optional number = numbers.stream() - .map( e -> e*2) - .collect(MoreCollectors.toOptional()); + Optional number = numbers + .stream() + .map(e -> e * 2) + .collect(MoreCollectors.toOptional()); - Assert.assertEquals(number.get(),new Integer(2)); + Assert.assertEquals(number.get(), new Integer(2)); } - @Test - public void onlyElementTest(){ + public void onlyElementTest() { List numbers = Arrays.asList(1); - Integer number = numbers.stream() - .map( e -> e*2) - .collect(MoreCollectors.onlyElement()); + Integer number = numbers + .stream() + .map(e -> e * 2) + .collect(MoreCollectors.onlyElement()); - Assert.assertEquals(number,new Integer(2)); + Assert.assertEquals(number, new Integer(2)); } - } diff --git a/guava21/src/test/java/StreamUtility.java b/guava21/src/test/java/StreamUtility.java index 91a03be48d..1eb866fb88 100644 --- a/guava21/src/test/java/StreamUtility.java +++ b/guava21/src/test/java/StreamUtility.java @@ -8,12 +8,12 @@ import java.util.stream.Stream; public class StreamUtility { - public static boolean assertStreamEquals(Stream stream1, Stream stream2){ + public static boolean assertStreamEquals(Stream stream1, Stream stream2) { Iterator iterator1 = stream1.iterator(); Iterator iterator2 = stream2.iterator(); - while (iterator1.hasNext()){ + while (iterator1.hasNext()) { Assert.assertEquals(iterator1.next(), iterator2.next()); } @@ -27,7 +27,7 @@ public class StreamUtility { Iterator iterator1 = stream1.iterator(); Iterator iterator2 = stream2.iterator(); - while (iterator1.hasNext()){ + while (iterator1.hasNext()) { Assert.assertEquals(iterator1.next(), iterator2.next()); } @@ -41,7 +41,7 @@ public class StreamUtility { Iterator iterator1 = stream1.iterator(); Iterator iterator2 = stream2.iterator(); - while (iterator1.hasNext()){ + while (iterator1.hasNext()) { Assert.assertEquals(iterator1.next(), iterator2.next()); } @@ -55,7 +55,7 @@ public class StreamUtility { Iterator iterator1 = stream1.iterator(); Iterator iterator2 = stream2.iterator(); - while (iterator1.hasNext()){ + while (iterator1.hasNext()) { Assert.assertEquals(iterator1.next(), iterator2.next()); } From 99688e9b19bc1bc2f5c06996b3d988ce42d5ec34 Mon Sep 17 00:00:00 2001 From: Danil Kornishev Date: Thu, 30 Mar 2017 16:27:22 -0400 Subject: [PATCH 216/291] Spring State Machine x3 (#1538) * [Fix] Move stateDo onto a separate state * Change tests to spring runner --- spring-state-machine/pom.xml | 7 +++- .../SimpleStateMachineConfiguration.java | 21 ++++++++--- .../ForkJoinStateMachineTest.java | 29 +++++++++++---- .../HierarchicalStateMachineTest.java | 27 +++++++++++--- .../JunctionStateMachineTest.java | 26 +++++++++++-- .../statemachine/StateEnumMachineTest.java | 17 ++++++++- .../StateMachineIntegrationTest.java | 37 ++++++++++++++----- 7 files changed, 130 insertions(+), 34 deletions(-) diff --git a/spring-state-machine/pom.xml b/spring-state-machine/pom.xml index bec03c39e8..f04d706d47 100644 --- a/spring-state-machine/pom.xml +++ b/spring-state-machine/pom.xml @@ -21,10 +21,15 @@ spring-statemachine-core 1.2.3.RELEASE + + org.springframework + spring-test + 4.3.7.RELEASE + junit junit - 4.11 + 4.12 test diff --git a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java index e9b448f6e7..f6c7991cf6 100644 --- a/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java +++ b/spring-state-machine/src/main/java/com/baeldung/spring/statemachine/config/SimpleStateMachineConfiguration.java @@ -36,10 +36,10 @@ public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapt .initial("SI") .end("SF") .states(new HashSet<>(Arrays.asList("S1", "S2"))) - .state("S4", executeAction(), errorAction()) .stateEntry("S3", entryAction()) - .stateDo("S3", executeAction()) - .stateExit("S3", exitAction()); + .stateExit("S3", exitAction()) + .state("S4", executeAction(), errorAction()) + .stateDo("S5", executeAction()); } @@ -52,9 +52,11 @@ public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapt .and().withExternal() .source("SI").target("S3").event("E3") .and().withExternal() - .source("S3").target("S4").event("E4").and().withExternal().source("S4").target("SF").event("end").guard(simpleGuard()) + .source("S3").target("S4").event("E4") .and().withExternal() - .source("S2").target("SF").event("end"); + .source("S4").target("S5").event("E5") + .and().withExternal() + .source("S5").target("SF").event("end").guard(simpleGuard()); } @Bean @@ -73,9 +75,16 @@ public class SimpleStateMachineConfiguration extends StateMachineConfigurerAdapt } @Bean - public Action executeAction() { + public Action doAction() { return (ctx) -> { LOGGER.info("Do " + ctx.getTarget().getId()); + }; + } + + @Bean + public Action executeAction() { + return (ctx) -> { + LOGGER.info("Execute " + ctx.getTarget().getId()); int approvals = (int) ctx.getExtendedState().getVariables().getOrDefault("approvalCount", 0); approvals++; ctx.getExtendedState().getVariables().put("approvalCount", approvals); diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java index 7b4b1928ea..03cb101a9d 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java @@ -1,23 +1,36 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.ForkJoinStateMachineConfiguration; +import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ForkJoinStateMachineConfiguration.class) public class ForkJoinStateMachineTest { + @Resource + private StateMachine stateMachine; + + @Before + public void setUp() { + stateMachine.start(); + } + @Test public void whenForkStateEntered_thenMultipleSubStatesEntered() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - boolean success = stateMachine.sendEvent("E1"); assertTrue(success); @@ -27,9 +40,6 @@ public class ForkJoinStateMachineTest { @Test public void whenAllConfiguredJoinEntryStatesAreEntered_thenTransitionToJoinState() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ForkJoinStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); boolean success = stateMachine.sendEvent("E1"); @@ -41,4 +51,9 @@ public class ForkJoinStateMachineTest { assertTrue(stateMachine.sendEvent("sub2")); assertEquals("SJoin", stateMachine.getState().getId()); } + + @After + public void tearDown() { + stateMachine.stop(); + } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java index d2944be173..950414bb0e 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java @@ -1,23 +1,35 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.config.HierarchicalStateMachineConfiguration; +import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import javax.annotation.Resource; import java.util.Arrays; import static org.junit.Assert.assertEquals; - +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = HierarchicalStateMachineConfiguration.class) public class HierarchicalStateMachineTest { + @Resource + private StateMachine stateMachine; + + @Before + public void setUp() { + stateMachine.start(); + } + @Test public void whenTransitionToSubMachine_thenSubStateIsEntered() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(HierarchicalStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); - assertEquals(Arrays.asList("SI", "SUB1"), stateMachine.getState().getIds()); @@ -34,4 +46,9 @@ public class HierarchicalStateMachineTest { assertEquals(1, stateMachine.getState().getIds().size()); assertEquals("SF", stateMachine.getState().getId()); } + + @After + public void tearDown() { + stateMachine.stop(); + } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java index f01683638b..64930162fd 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java @@ -1,18 +1,33 @@ package com.baeldung.spring.statemachine; +import com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration; +import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import javax.annotation.Resource; +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = JunctionStateMachineConfiguration.class) public class JunctionStateMachineTest { + @Resource + private StateMachine stateMachine; + + @Before + public void setUp() { + stateMachine.start(); + } + @Test public void whenTransitioningToJunction_thenArriveAtSubJunctionNode() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(com.baeldung.spring.statemachine.config.JunctionStateMachineConfiguration.class); - StateMachine stateMachine = ctx.getBean(StateMachine.class); - stateMachine.start(); stateMachine.sendEvent("E1"); Assert.assertEquals("low", stateMachine.getState().getId()); @@ -20,4 +35,9 @@ public class JunctionStateMachineTest { stateMachine.sendEvent("end"); Assert.assertEquals("SF", stateMachine.getState().getId()); } + + @After + public void tearDown() { + stateMachine.stop(); + } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java index 257ed8768c..b7cbebe145 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java @@ -3,22 +3,30 @@ package com.baeldung.spring.statemachine; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewEvents; import com.baeldung.spring.statemachine.applicationreview.ApplicationReviewStates; import com.baeldung.spring.statemachine.config.SimpleEnumStateMachineConfiguration; +import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.statemachine.StateMachine; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.annotation.Resource; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = SimpleEnumStateMachineConfiguration.class) public class StateEnumMachineTest { + @Resource private StateMachine stateMachine; @Before public void setUp() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SimpleEnumStateMachineConfiguration.class); - stateMachine = ctx.getBean(StateMachine.class); stateMachine.start(); } @@ -29,4 +37,9 @@ public class StateEnumMachineTest { assertTrue(stateMachine.sendEvent(ApplicationReviewEvents.REJECT)); assertEquals(ApplicationReviewStates.REJECTED, stateMachine.getState().getId()); } + + @After + public void tearDown() { + stateMachine.stop(); + } } diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index d7b26eeb97..8f61d93105 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -1,23 +1,31 @@ package com.baeldung.spring.statemachine; -import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; -import org.junit.Before; -import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.statemachine.StateMachine; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.statemachine.StateMachine; + +import com.baeldung.spring.statemachine.config.SimpleStateMachineConfiguration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = SimpleStateMachineConfiguration.class) public class StateMachineIntegrationTest { - private AnnotationConfigApplicationContext ctx; + @Resource private StateMachine stateMachine; @Before public void setUp() { - ctx = new AnnotationConfigApplicationContext(SimpleStateMachineConfiguration.class); - stateMachine = ctx.getBean(StateMachine.class); stateMachine.start(); } @@ -42,9 +50,18 @@ public class StateMachineIntegrationTest { assertTrue(acceptedE4); assertEquals("S4", stateMachine.getState().getId()); - assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount")); + + stateMachine.sendEvent("E5"); + assertEquals("S5", stateMachine.getState().getId()); stateMachine.sendEvent("end"); assertEquals("SF", stateMachine.getState().getId()); + + assertEquals(2, stateMachine.getExtendedState().getVariables().get("approvalCount")); + } + + @After + public void tearDown() { + stateMachine.stop(); } } From d3590de13cb75a3d39553f2d78ecf1afe2b65e98 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Fri, 31 Mar 2017 02:40:45 +0530 Subject: [PATCH 217/291] ratpack with google guice (#1542) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * changing banner format in plain text * Delete banner.txt~ * Delete b.txt~ * CORS in JAX-RS * ratpack with google guice --- .../java/com/baeldung/guice/Application.java | 31 ++++ .../guice/config/DependencyModule.java | 16 ++ .../guice/service/DataPumpService.java | 11 ++ .../service/impl/DataPumpServiceImpl.java | 14 ++ .../java/com/baeldung/ApplicationTest.java | 13 +- resteasy/bin/README.md | 8 + resteasy/bin/pom.xml | 171 ++++++++++++++++++ .../main/webapp/WEB-INF/classes/logback.xml | 3 + .../WEB-INF/jboss-deployment-structure.xml | 13 ++ .../bin/src/main/webapp/WEB-INF/jboss-web.xml | 4 + resteasy/bin/src/main/webapp/WEB-INF/web.xml | 13 ++ resteasy/bin/src/main/webapp/script.js | 16 ++ .../com/baeldung/server/movies/batman.json | 4 + .../baeldung/server/movies/transformer.json | 4 + 14 files changed, 317 insertions(+), 4 deletions(-) create mode 100644 ratpack/src/main/java/com/baeldung/guice/Application.java create mode 100644 ratpack/src/main/java/com/baeldung/guice/config/DependencyModule.java create mode 100644 ratpack/src/main/java/com/baeldung/guice/service/DataPumpService.java create mode 100644 ratpack/src/main/java/com/baeldung/guice/service/impl/DataPumpServiceImpl.java create mode 100644 resteasy/bin/README.md create mode 100644 resteasy/bin/pom.xml create mode 100644 resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml create mode 100644 resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml create mode 100644 resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml create mode 100644 resteasy/bin/src/main/webapp/WEB-INF/web.xml create mode 100644 resteasy/bin/src/main/webapp/script.js create mode 100644 resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json create mode 100644 resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json diff --git a/ratpack/src/main/java/com/baeldung/guice/Application.java b/ratpack/src/main/java/com/baeldung/guice/Application.java new file mode 100644 index 0000000000..39d29b9b2b --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/guice/Application.java @@ -0,0 +1,31 @@ +package com.baeldung.guice; + +import com.baeldung.guice.config.DependencyModule; +import com.baeldung.guice.service.DataPumpService; +import com.baeldung.guice.service.impl.DataPumpServiceImpl; + +import ratpack.guice.Guice; +import ratpack.server.RatpackServer; + +public class Application { + + public static void main(String[] args) throws Exception { + + RatpackServer + .start(server -> server.registry(Guice.registry(bindings -> bindings.module(DependencyModule.class))) + .handlers(chain -> chain.get("randomString", ctx -> { + DataPumpService dataPumpService = ctx.get(DataPumpService.class); + ctx.render(dataPumpService.generate().length()); + }))); + +// RatpackServer.start(server -> server +// .registry(Guice +// .registry(bindings -> bindings.bindInstance(DataPumpService.class, new DataPumpServiceImpl()))) +// .handlers(chain -> chain.get("randomString", ctx -> { +// DataPumpService dataPumpService = ctx.get(DataPumpService.class); +// ctx.render(dataPumpService.generate()); +// }))); + + } + +} diff --git a/ratpack/src/main/java/com/baeldung/guice/config/DependencyModule.java b/ratpack/src/main/java/com/baeldung/guice/config/DependencyModule.java new file mode 100644 index 0000000000..1824578501 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/guice/config/DependencyModule.java @@ -0,0 +1,16 @@ +package com.baeldung.guice.config; + +import com.baeldung.guice.service.DataPumpService; +import com.baeldung.guice.service.impl.DataPumpServiceImpl; +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; + +public class DependencyModule extends AbstractModule { + + @Override + protected void configure() { + bind(DataPumpService.class).to(DataPumpServiceImpl.class) + .in(Scopes.SINGLETON); + } + +} diff --git a/ratpack/src/main/java/com/baeldung/guice/service/DataPumpService.java b/ratpack/src/main/java/com/baeldung/guice/service/DataPumpService.java new file mode 100644 index 0000000000..6adfec2365 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/guice/service/DataPumpService.java @@ -0,0 +1,11 @@ +package com.baeldung.guice.service; + +import com.baeldung.guice.service.impl.DataPumpServiceImpl; +import com.google.inject.ImplementedBy; + +@ImplementedBy(DataPumpServiceImpl.class) +public interface DataPumpService { + + String generate(); + +} diff --git a/ratpack/src/main/java/com/baeldung/guice/service/impl/DataPumpServiceImpl.java b/ratpack/src/main/java/com/baeldung/guice/service/impl/DataPumpServiceImpl.java new file mode 100644 index 0000000000..88f171f8a2 --- /dev/null +++ b/ratpack/src/main/java/com/baeldung/guice/service/impl/DataPumpServiceImpl.java @@ -0,0 +1,14 @@ +package com.baeldung.guice.service.impl; + +import java.util.UUID; + +import com.baeldung.guice.service.DataPumpService; + +public class DataPumpServiceImpl implements DataPumpService { + + @Override + public String generate() { + return UUID.randomUUID().toString(); + } + +} diff --git a/ratpack/src/test/java/com/baeldung/ApplicationTest.java b/ratpack/src/test/java/com/baeldung/ApplicationTest.java index 0333441928..047575ca6e 100644 --- a/ratpack/src/test/java/com/baeldung/ApplicationTest.java +++ b/ratpack/src/test/java/com/baeldung/ApplicationTest.java @@ -24,22 +24,27 @@ public class ApplicationTest { public void givenDefaultUrl_getStaticText() { assertEquals("Welcome to baeldung ratpack!!!", appUnderTest.getHttpClient().getText("/")); } - + @Test public void givenDynamicUrl_getDynamicText() { assertEquals("Hello dummybot!!!", appUnderTest.getHttpClient().getText("/dummybot")); } - + @Test public void givenUrl_getListOfEmployee() throws JsonProcessingException { List employees = new ArrayList(); ObjectMapper mapper = new ObjectMapper(); employees.add(new Employee(1L, "Mr", "John Doe")); employees.add(new Employee(2L, "Mr", "White Snow")); - + assertEquals(mapper.writeValueAsString(employees), appUnderTest.getHttpClient().getText("/data/employees")); } - + + @Test + public void givenStaticUrl_getDynamicText() { + assertEquals(21, appUnderTest.getHttpClient().getText("/randomString").length()); + } + @After public void shutdown() { appUnderTest.close(); diff --git a/resteasy/bin/README.md b/resteasy/bin/README.md new file mode 100644 index 0000000000..722f1dfe93 --- /dev/null +++ b/resteasy/bin/README.md @@ -0,0 +1,8 @@ +========= + +## A Guide to RESTEasy + + +### Relevant Articles: +- [A Guide to RESTEasy](http://www.baeldung.com/resteasy-tutorial) +- [RESTEasy Client API](http://www.baeldung.com/resteasy-client-tutorial) diff --git a/resteasy/bin/pom.xml b/resteasy/bin/pom.xml new file mode 100644 index 0000000000..f0bd8298f5 --- /dev/null +++ b/resteasy/bin/pom.xml @@ -0,0 +1,171 @@ + + + 4.0.0 + + com.baeldung + resteasy-tutorial + 1.0 + war + + + 3.0.19.Final + 4.12 + 2.5 + 2.19.1 + 1.6.1 + + + + RestEasyTutorial + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + true + + jetty8x + embedded + + + + 8082 + + + + + + + + + + + + + org.jboss.resteasy + resteasy-servlet-initializer + ${resteasy.version} + + + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + + + + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + + + + org.jboss.resteasy + resteasy-jackson-provider + ${resteasy.version} + + + + + + junit + junit + ${junit.version} + + + + commons-io + commons-io + ${commons-io.version} + + + + + + + live + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*IntegrationTest.java + + + **/*LiveTest.java + + + + + + + json + + + + + org.codehaus.cargo + cargo-maven2-plugin + ${cargo-maven2-plugin.version} + + false + + + + start-server + pre-integration-test + + start + + + + stop-server + post-integration-test + + stop + + + + + + + + + + + \ No newline at end of file diff --git a/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml b/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml new file mode 100644 index 0000000000..d94e9f71ab --- /dev/null +++ b/resteasy/bin/src/main/webapp/WEB-INF/classes/logback.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml new file mode 100644 index 0000000000..cb258374a1 --- /dev/null +++ b/resteasy/bin/src/main/webapp/WEB-INF/jboss-deployment-structure.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml b/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml new file mode 100644 index 0000000000..694bb71332 --- /dev/null +++ b/resteasy/bin/src/main/webapp/WEB-INF/jboss-web.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resteasy/bin/src/main/webapp/WEB-INF/web.xml b/resteasy/bin/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..d5f00293f4 --- /dev/null +++ b/resteasy/bin/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,13 @@ + + + + RestEasy Example + + + resteasy.servlet.mapping.prefix + /rest + + + \ No newline at end of file diff --git a/resteasy/bin/src/main/webapp/script.js b/resteasy/bin/src/main/webapp/script.js new file mode 100644 index 0000000000..88198887b0 --- /dev/null +++ b/resteasy/bin/src/main/webapp/script.js @@ -0,0 +1,16 @@ +function call(url, type, data) { + var request = $.ajax({ + url : url, + method : "GET", + data : (data) ? JSON.stringify(data) : "", + dataType : type + }); + + request.done(function(resp) { + console.log(resp); + }); + + request.fail(function(jqXHR, textStatus) { + console.log("Request failed: " + textStatus); + }); +}; \ No newline at end of file diff --git a/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json b/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json new file mode 100644 index 0000000000..82aaaa8f40 --- /dev/null +++ b/resteasy/bin/src/test/resources/com/baeldung/server/movies/batman.json @@ -0,0 +1,4 @@ +{ + "title": "Batman", + "imdbId": "tt0096895" +} \ No newline at end of file diff --git a/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json b/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json new file mode 100644 index 0000000000..634cefc73c --- /dev/null +++ b/resteasy/bin/src/test/resources/com/baeldung/server/movies/transformer.json @@ -0,0 +1,4 @@ +{ + "title": "Transformers", + "imdbId": "tt0418279" +} \ No newline at end of file From 626db733b9c161e68a3fcaf0728f4b7a26cf9634 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 31 Mar 2017 12:25:37 +0200 Subject: [PATCH 218/291] Corrected Indentation using formatter. (#1541) (#1544) --- .../com/baeldung/SimpleServerVerticle.java | 6 ++-- ...> RestServiceVerticleIntegrationTest.java} | 2 +- ... SimpleServerVerticleIntegrationTest.java} | 33 +++++++++---------- 3 files changed, 18 insertions(+), 23 deletions(-) rename vertx/src/test/java/com/baeldung/{RestServiceVerticleTest.java => RestServiceVerticleIntegrationTest.java} (96%) rename vertx/src/test/java/com/baeldung/{SimpleServerVerticleTest.java => SimpleServerVerticleIntegrationTest.java} (58%) diff --git a/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java index 6b56896860..96aa058ce7 100644 --- a/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java +++ b/vertx/src/main/java/com/baeldung/SimpleServerVerticle.java @@ -8,10 +8,8 @@ public class SimpleServerVerticle extends AbstractVerticle { @Override public void start(Future future) { vertx.createHttpServer() - .requestHandler(request -> { - request.response() - .end("Welcome to Vert.x Intro"); - }) + .requestHandler( + r -> r.response().end("Welcome to Vert.x Intro")) .listen(config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { future.complete(); diff --git a/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java b/vertx/src/test/java/com/baeldung/RestServiceVerticleIntegrationTest.java similarity index 96% rename from vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java rename to vertx/src/test/java/com/baeldung/RestServiceVerticleIntegrationTest.java index b5be0734f4..f08d9ffde1 100644 --- a/vertx/src/test/java/com/baeldung/RestServiceVerticleTest.java +++ b/vertx/src/test/java/com/baeldung/RestServiceVerticleIntegrationTest.java @@ -13,7 +13,7 @@ import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; @RunWith(VertxUnitRunner.class) -public class RestServiceVerticleTest { +public class RestServiceVerticleIntegrationTest { private Vertx vertx; diff --git a/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java b/vertx/src/test/java/com/baeldung/SimpleServerVerticleIntegrationTest.java similarity index 58% rename from vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java rename to vertx/src/test/java/com/baeldung/SimpleServerVerticleIntegrationTest.java index 189d2f6604..194f403e25 100644 --- a/vertx/src/test/java/com/baeldung/SimpleServerVerticleTest.java +++ b/vertx/src/test/java/com/baeldung/SimpleServerVerticleIntegrationTest.java @@ -1,27 +1,23 @@ package com.baeldung; +import io.vertx.core.Vertx; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import io.vertx.core.DeploymentOptions; -import io.vertx.core.Vertx; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; - @RunWith(VertxUnitRunner.class) -public class SimpleServerVerticleTest { +public class SimpleServerVerticleIntegrationTest { private Vertx vertx; @Before public void setup(TestContext testContext) { vertx = Vertx.vertx(); - vertx.deployVerticle(SimpleServerVerticle.class.getName(), - testContext.asyncAssertSuccess()); + vertx.deployVerticle(SimpleServerVerticle.class.getName(), testContext.asyncAssertSuccess()); } @After @@ -33,14 +29,15 @@ public class SimpleServerVerticleTest { public void whenReceivedResponse_thenSuccess(TestContext testContext) { final Async async = testContext.async(); - vertx.createHttpClient() - .getNow(8080, "localhost", "/", response -> { - response.handler(responseBody -> { - testContext.assertTrue(responseBody.toString() - .contains("Welcome")); - async.complete(); - }); - }); + vertx + .createHttpClient() + .getNow(8080, "localhost", "/", + response -> response.handler(responseBody -> { + testContext.assertTrue(responseBody + .toString() + .contains("Welcome")); + async.complete(); + })); } } From c73c25292424574d09daef7dc588446a170aeec2 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Fri, 31 Mar 2017 06:54:17 -0500 Subject: [PATCH 219/291] BAEL-680 and BAEL-756 README files (#1539) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates --- core-java/README.md | 1 + kotlin/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/core-java/README.md b/core-java/README.md index 63e3748ec6..0861ee7c5e 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -84,4 +84,5 @@ - [Guide to java.util.concurrent.Locks](http://www.baeldung.com/java-concurrent-locks) - [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) - [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) +- [Guide to Java 8 Comparator.comparing()](http://www.baeldung.com/java-8-comparator-comparing) diff --git a/kotlin/README.md b/kotlin/README.md index ceebde4573..309aafa4b6 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -2,3 +2,4 @@ - [Introduction to the Kotlin Language](http://www.baeldung.com/kotlin) - [A guide to the “when{}†block in Kotlin](http://www.baeldung.com/kotlin-when) +- [Comprehensive Guide to Null Safety in Kotlin](http://www.baeldung.com/kotlin-null-safety) From 4daef51161c2903f7b826278406e6ac649e920d8 Mon Sep 17 00:00:00 2001 From: Nikhil Khatwani Date: Fri, 31 Mar 2017 22:17:58 +0530 Subject: [PATCH 220/291] BAEL-711 Guide_to_Microservices_using_lagom_framework Changes (#1495) * BAEL_711_Guide_to_Microservices_using_lagom_framework Changes * BAEL_711_Guide_to_Microservices_using_lagom_framework_v2 * BAEL_711_Guide_to_Microservices_using_lagom-Review Comments --- lagom/.gitignore | 4 ++ lagom/README | 40 ++++++++++++++++ lagom/build.sbt | 41 ++++++++++++++++ .../greeting/api/GreetingService.java | 23 +++++++++ lagom/greeting-impl/bin/application.conf | 1 + .../bin/classes/application.conf | 1 + .../greeting/impl/GreetingCommand.java | 29 +++++++++++ .../greeting/impl/GreetingEntity.java | 32 +++++++++++++ .../greeting/impl/GreetingEvent.java | 23 +++++++++ .../greeting/impl/GreetingServiceImpl.java | 48 +++++++++++++++++++ .../greeting/impl/GreetingServiceModule.java | 18 +++++++ .../greeting/impl/GreetingState.java | 24 ++++++++++ .../src/main/resources/application.conf | 1 + lagom/project/build.properties | 1 + lagom/project/plugins.sbt | 2 + .../weather/api/WeatherService.java | 28 +++++++++++ .../helloworld/weather/api/WeatherStats.java | 32 +++++++++++++ lagom/weather-impl/bin/application.conf | 1 + .../weather/impl/WeatherServiceImpl.java | 19 ++++++++ .../weather/impl/WeatherServiceModule.java | 16 +++++++ .../src/main/resources/application.conf | 1 + 21 files changed, 385 insertions(+) create mode 100644 lagom/.gitignore create mode 100644 lagom/README create mode 100644 lagom/build.sbt create mode 100644 lagom/greeting-api/src/main/java/org/baeldung/lagom/helloworld/greeting/api/GreetingService.java create mode 100644 lagom/greeting-impl/bin/application.conf create mode 100644 lagom/greeting-impl/bin/classes/application.conf create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingCommand.java create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEntity.java create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEvent.java create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceImpl.java create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceModule.java create mode 100644 lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingState.java create mode 100644 lagom/greeting-impl/src/main/resources/application.conf create mode 100644 lagom/project/build.properties create mode 100644 lagom/project/plugins.sbt create mode 100644 lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherService.java create mode 100644 lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherStats.java create mode 100644 lagom/weather-impl/bin/application.conf create mode 100644 lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceImpl.java create mode 100644 lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceModule.java create mode 100644 lagom/weather-impl/src/main/resources/application.conf diff --git a/lagom/.gitignore b/lagom/.gitignore new file mode 100644 index 0000000000..5e521241aa --- /dev/null +++ b/lagom/.gitignore @@ -0,0 +1,4 @@ +greeting-impl/logs/* +lagom-hello-world/greeting-impl/bin/classes/* +lagom-hello-world/logs/application.log +lagom-hello-world/weather-impl/logs/application.log diff --git a/lagom/README b/lagom/README new file mode 100644 index 0000000000..0d81a4b3c1 --- /dev/null +++ b/lagom/README @@ -0,0 +1,40 @@ +Steps to setup from scratch + +1) Create sbt build file "build.sbt" +2) Create plugins file project/plugins.sbt +3) Create build properties file project/build.properties +4) Run sbt command from project root to generate project directories, generated projects at target/lagom-dynamic-projects + Service Locator project: lagom-internal-meta-project-service-locator + cassandra project: lagom-internal-meta-project-cassandra +5) Create folders in all projects to follow maven like directory structure layout for project source code: src/main/java and src/main/java/resources and test folders. +6) Weather microservice + a) WeatherService Interface with method: + weatherStatsForToday() + b) WeatherServiceImpl to return weatherstats from a random list of weather stats + +7) Greeting Microservice + GreetingService Interface: + handleGreetFrom(String user) + + a) Reply back to user with greeting message("Hello") along with weather stats fetched from weather microservice + b) Update the greeting message("Hello Again") for an existing user. + +8) GreetingEntity: PersistentEntity + a) handles ReceivedGreetingCommand + b) Stores ReceivedGreetingEvent events to cassandra + c) Processes ReceivedGreetingEvent to update GreetingState("Hello" to "Hello Again") if required. + +9) Register modules with lagom using application.conf files. +10) Run project: sbt lagom:runAll + + +Sample Run: +curl http://localhost:9000/api/greeting/Nikhil; +Hello Nikhil! Today's weather stats: Going to be very humid, Take Water + +curl http://localhost:9000/api/greeting/Nikhil; +Hello Again Nikhil! Today's weather stats: Going to Rain, Take Umbrella + + + + diff --git a/lagom/build.sbt b/lagom/build.sbt new file mode 100644 index 0000000000..064d67468e --- /dev/null +++ b/lagom/build.sbt @@ -0,0 +1,41 @@ +organization in ThisBuild := "org.baeldung" + +// the Scala version that will be used for cross-compiled libraries +scalaVersion in ThisBuild := "2.11.7" + +lagomKafkaEnabled in ThisBuild := false + +lazy val greetingApi = project("greeting-api") + .settings( + version := "1.0-SNAPSHOT", + libraryDependencies ++= Seq( + lagomJavadslApi + ) + ) + +lazy val greetingImpl = project("greeting-impl") + .enablePlugins(LagomJava) + .settings( + version := "1.0-SNAPSHOT", + libraryDependencies ++= Seq( + lagomJavadslPersistenceCassandra + ) + ) + .dependsOn(greetingApi, weatherApi) + +lazy val weatherApi = project("weather-api") + .settings( + version := "1.0-SNAPSHOT", + libraryDependencies ++= Seq( + lagomJavadslApi + ) + ) + +lazy val weatherImpl = project("weather-impl") + .enablePlugins(LagomJava) + .settings( + version := "1.0-SNAPSHOT" + ) + .dependsOn(weatherApi) + +def project(id: String) = Project(id, base = file(id)) \ No newline at end of file diff --git a/lagom/greeting-api/src/main/java/org/baeldung/lagom/helloworld/greeting/api/GreetingService.java b/lagom/greeting-api/src/main/java/org/baeldung/lagom/helloworld/greeting/api/GreetingService.java new file mode 100644 index 0000000000..93567f0185 --- /dev/null +++ b/lagom/greeting-api/src/main/java/org/baeldung/lagom/helloworld/greeting/api/GreetingService.java @@ -0,0 +1,23 @@ +package org.baeldung.lagom.helloworld.greeting.api; + +import static com.lightbend.lagom.javadsl.api.Service.named; +import static com.lightbend.lagom.javadsl.api.Service.restCall; + +import com.lightbend.lagom.javadsl.api.Descriptor; +import com.lightbend.lagom.javadsl.api.Service; +import com.lightbend.lagom.javadsl.api.ServiceCall; +import com.lightbend.lagom.javadsl.api.transport.Method; + +import akka.NotUsed; + +public interface GreetingService extends Service { + + public ServiceCall handleGreetFrom(String user); + + @Override + default Descriptor descriptor() { + return named("greetingservice").withCalls( + restCall(Method.GET, "/api/greeting/:fromUser", this::handleGreetFrom) + ).withAutoAcl(true); + } +} \ No newline at end of file diff --git a/lagom/greeting-impl/bin/application.conf b/lagom/greeting-impl/bin/application.conf new file mode 100644 index 0000000000..1e78ce4a79 --- /dev/null +++ b/lagom/greeting-impl/bin/application.conf @@ -0,0 +1 @@ +play.modules.enabled += org.baeldung.lagom.helloworld.greeting.impl.GreetingServiceModule \ No newline at end of file diff --git a/lagom/greeting-impl/bin/classes/application.conf b/lagom/greeting-impl/bin/classes/application.conf new file mode 100644 index 0000000000..1e78ce4a79 --- /dev/null +++ b/lagom/greeting-impl/bin/classes/application.conf @@ -0,0 +1 @@ +play.modules.enabled += org.baeldung.lagom.helloworld.greeting.impl.GreetingServiceModule \ No newline at end of file diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingCommand.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingCommand.java new file mode 100644 index 0000000000..be9e713ec9 --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingCommand.java @@ -0,0 +1,29 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.common.base.Preconditions; +import com.lightbend.lagom.javadsl.persistence.PersistentEntity; +import com.lightbend.lagom.serialization.CompressedJsonable; +import com.lightbend.lagom.serialization.Jsonable; + +public interface GreetingCommand extends Jsonable { + + @SuppressWarnings("serial") + @JsonDeserialize + public final class ReceivedGreetingCommand implements GreetingCommand, + CompressedJsonable, PersistentEntity.ReplyType { + private final String fromUser; + + @JsonCreator + public ReceivedGreetingCommand(String fromUser) { + this.fromUser = Preconditions.checkNotNull(fromUser, "fromUser"); + } + + public String getFromUser() { + return fromUser; + } + + } + +} diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEntity.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEntity.java new file mode 100644 index 0000000000..91fc74039d --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEntity.java @@ -0,0 +1,32 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import java.util.Optional; + +import org.baeldung.lagom.helloworld.greeting.impl.GreetingCommand.ReceivedGreetingCommand; +import org.baeldung.lagom.helloworld.greeting.impl.GreetingEvent.ReceivedGreetingEvent; + +import com.lightbend.lagom.javadsl.persistence.PersistentEntity; + +public class GreetingEntity extends PersistentEntity { + + @Override + public Behavior initialBehavior(Optional snapshotState) { + BehaviorBuilder b = newBehaviorBuilder(new GreetingState("Hello ")); + + b.setCommandHandler(ReceivedGreetingCommand.class, + (cmd, ctx) -> { + String fromUser = cmd.getFromUser(); + String currentGreeting = state().getMessage(); + return ctx.thenPersist( + new ReceivedGreetingEvent(fromUser), + evt -> ctx.reply(currentGreeting + fromUser + "!")); + }); + + b.setEventHandler(ReceivedGreetingEvent.class, + // We simply update the current state + evt -> state().withMessage("Hello Again ")); + + return b.build(); + } +} diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEvent.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEvent.java new file mode 100644 index 0000000000..e454f6cd1b --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingEvent.java @@ -0,0 +1,23 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.lightbend.lagom.serialization.Jsonable; + + +public interface GreetingEvent extends Jsonable { + + class ReceivedGreetingEvent implements GreetingEvent { + private final String fromUser; + + @JsonCreator + public ReceivedGreetingEvent(String fromUser) { + this.fromUser = fromUser; + } + + public String getFromUser() { + return fromUser; + } + + } + +} diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceImpl.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceImpl.java new file mode 100644 index 0000000000..c28687291e --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceImpl.java @@ -0,0 +1,48 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import org.baeldung.lagom.helloworld.greeting.api.GreetingService; +import org.baeldung.lagom.helloworld.greeting.impl.GreetingCommand.ReceivedGreetingCommand; +import org.baeldung.lagom.helloworld.weather.api.WeatherService; +import org.baeldung.lagom.helloworld.weather.api.WeatherStats; + +import com.google.inject.Inject; +import com.lightbend.lagom.javadsl.api.ServiceCall; +import com.lightbend.lagom.javadsl.persistence.PersistentEntityRef; +import com.lightbend.lagom.javadsl.persistence.PersistentEntityRegistry; + +import akka.NotUsed; + +public class GreetingServiceImpl implements GreetingService { + + private final PersistentEntityRegistry persistentEntityRegistry; + private final WeatherService weatherService; + + @Inject + public GreetingServiceImpl(PersistentEntityRegistry persistentEntityRegistry, WeatherService weatherService) { + this.persistentEntityRegistry = persistentEntityRegistry; + this.weatherService = weatherService; + persistentEntityRegistry.register(GreetingEntity.class); + } + + @Override + public ServiceCall handleGreetFrom(String user) { + return request -> { + // Look up the hello world entity for the given ID. + PersistentEntityRef ref = persistentEntityRegistry.refFor(GreetingEntity.class, user); + CompletableFuture greetingResponse = ref.ask(new ReceivedGreetingCommand(user)) + .toCompletableFuture(); + CompletableFuture todaysWeatherInfo = + (CompletableFuture) weatherService.weatherStatsForToday().invoke(); + try { + return CompletableFuture.completedFuture(greetingResponse.get() + + " Today's weather stats: " + todaysWeatherInfo.get().getMessage()); + } catch (InterruptedException | ExecutionException e) { + return CompletableFuture.completedFuture("Sorry Some Error at our end, working on it"); + } + }; + } + +} diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceModule.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceModule.java new file mode 100644 index 0000000000..4813e91a7c --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingServiceModule.java @@ -0,0 +1,18 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import org.baeldung.lagom.helloworld.greeting.api.GreetingService; +import org.baeldung.lagom.helloworld.weather.api.WeatherService; + +import com.google.inject.AbstractModule; +import com.lightbend.lagom.javadsl.server.ServiceGuiceSupport; + +/** + * The module that binds the GreetingService so that it can be served. + */ +public class GreetingServiceModule extends AbstractModule implements ServiceGuiceSupport { + @Override + protected void configure() { + bindServices(serviceBinding(GreetingService.class, GreetingServiceImpl.class)); + bindClient(WeatherService.class); + } +} diff --git a/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingState.java b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingState.java new file mode 100644 index 0000000000..125795601e --- /dev/null +++ b/lagom/greeting-impl/src/main/java/org/baeldung/lagom/helloworld/greeting/impl/GreetingState.java @@ -0,0 +1,24 @@ +package org.baeldung.lagom.helloworld.greeting.impl; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +@JsonDeserialize +public class GreetingState { + + private final String message; + + @JsonCreator + public GreetingState(String message) { + this.message = message; + } + + GreetingState withMessage(String message) { + return new GreetingState(message); + } + + public String getMessage() { + return message; + } + +} diff --git a/lagom/greeting-impl/src/main/resources/application.conf b/lagom/greeting-impl/src/main/resources/application.conf new file mode 100644 index 0000000000..1e78ce4a79 --- /dev/null +++ b/lagom/greeting-impl/src/main/resources/application.conf @@ -0,0 +1 @@ +play.modules.enabled += org.baeldung.lagom.helloworld.greeting.impl.GreetingServiceModule \ No newline at end of file diff --git a/lagom/project/build.properties b/lagom/project/build.properties new file mode 100644 index 0000000000..43b8278c68 --- /dev/null +++ b/lagom/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.11 diff --git a/lagom/project/plugins.sbt b/lagom/project/plugins.sbt new file mode 100644 index 0000000000..8b8e36a743 --- /dev/null +++ b/lagom/project/plugins.sbt @@ -0,0 +1,2 @@ +addSbtPlugin("com.lightbend.lagom" % "lagom-sbt-plugin" % "1.3.1") +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "3.0.0") diff --git a/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherService.java b/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherService.java new file mode 100644 index 0000000000..888109322b --- /dev/null +++ b/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherService.java @@ -0,0 +1,28 @@ +package org.baeldung.lagom.helloworld.weather.api; + +import static com.lightbend.lagom.javadsl.api.Service.named; +import static com.lightbend.lagom.javadsl.api.Service.*; + +import com.lightbend.lagom.javadsl.api.Descriptor; +import com.lightbend.lagom.javadsl.api.Service; +import com.lightbend.lagom.javadsl.api.ServiceCall; +import com.lightbend.lagom.javadsl.api.transport.Method; + +import akka.NotUsed; + +/** + * WeatherService Interface. + */ +public interface WeatherService extends Service { + + // Fetch Today's Weather Stats service call + public ServiceCall weatherStatsForToday(); + + @Override + default Descriptor descriptor() { + return named("weatherservice").withCalls( + restCall(Method.GET, "/api/weather", this::weatherStatsForToday) + ).withAutoAcl(true); + } + +} \ No newline at end of file diff --git a/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherStats.java b/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherStats.java new file mode 100644 index 0000000000..23530a297d --- /dev/null +++ b/lagom/weather-api/src/main/java/org/baeldung/lagom/helloworld/weather/api/WeatherStats.java @@ -0,0 +1,32 @@ +package org.baeldung.lagom.helloworld.weather.api; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public enum WeatherStats { + + STATS_RAINY("Going to Rain, Take Umbrella"), STATS_HUMID("Going to be very humid, Take Water"); + + private final String message; + + private static final List VALUES = Collections.unmodifiableList(Arrays.asList(values())); + + private static final int SIZE = VALUES.size(); + + private static final Random RANDOM = new Random(); + + WeatherStats(String msg) { + this.message = msg; + } + + public static WeatherStats forToday() { + return VALUES.get(RANDOM.nextInt(SIZE)); + } + + public String getMessage() { + return message; + } + +} diff --git a/lagom/weather-impl/bin/application.conf b/lagom/weather-impl/bin/application.conf new file mode 100644 index 0000000000..cf6cec2115 --- /dev/null +++ b/lagom/weather-impl/bin/application.conf @@ -0,0 +1 @@ +play.modules.enabled += org.baeldung.lagom.helloworld.weather.impl.WeatherServiceModule \ No newline at end of file diff --git a/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceImpl.java b/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceImpl.java new file mode 100644 index 0000000000..d7f97f9105 --- /dev/null +++ b/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceImpl.java @@ -0,0 +1,19 @@ +package org.baeldung.lagom.helloworld.weather.impl; + +import java.util.concurrent.CompletableFuture; + +import org.baeldung.lagom.helloworld.weather.api.WeatherService; +import org.baeldung.lagom.helloworld.weather.api.WeatherStats; + +import com.lightbend.lagom.javadsl.api.ServiceCall; + +import akka.NotUsed; + +public class WeatherServiceImpl implements WeatherService { + + @Override + public ServiceCall weatherStatsForToday() { + return (req) -> CompletableFuture.completedFuture(WeatherStats.forToday()); + } + +} diff --git a/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceModule.java b/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceModule.java new file mode 100644 index 0000000000..ac2834ff5c --- /dev/null +++ b/lagom/weather-impl/src/main/java/org/baeldung/lagom/helloworld/weather/impl/WeatherServiceModule.java @@ -0,0 +1,16 @@ +package org.baeldung.lagom.helloworld.weather.impl; + +import org.baeldung.lagom.helloworld.weather.api.WeatherService; + +import com.google.inject.AbstractModule; +import com.lightbend.lagom.javadsl.server.ServiceGuiceSupport; + +/** + * The module that binds the GreetingService so that it can be served. + */ +public class WeatherServiceModule extends AbstractModule implements ServiceGuiceSupport { + @Override + protected void configure() { + bindServices(serviceBinding(WeatherService.class, WeatherServiceImpl.class)); + } +} diff --git a/lagom/weather-impl/src/main/resources/application.conf b/lagom/weather-impl/src/main/resources/application.conf new file mode 100644 index 0000000000..cf6cec2115 --- /dev/null +++ b/lagom/weather-impl/src/main/resources/application.conf @@ -0,0 +1 @@ +play.modules.enabled += org.baeldung.lagom.helloworld.weather.impl.WeatherServiceModule \ No newline at end of file From 0975123b837608bf067466d6dfb09f0ad00bb20c Mon Sep 17 00:00:00 2001 From: Tomasz Sobala Date: Fri, 31 Mar 2017 19:33:34 +0200 Subject: [PATCH 221/291] Exploring the Spring Boot TestRestTemplate (#1550) * injecting beans * XML-based configuration replaced with Java Config. * [BAEL-431] Exploring TestRestTemplate. * Revert of evaluation task "XML-based configuration replaced with Java Config." This reverts commit 66471cf0574c85f8ff514ec4caf5ba44ebba1a74. * Revert of evaluation task "injecting beans" This reverts commit d2ac20185e636245bc0ae0b4ccb952965de88e28. * [BAEL-431] fix to the tests in TestRestTemplateBasicLiveTest. * [BAEL-431] added more meaningful user and password for auth. --- .../client/TestRestTemplateBasicLiveTest.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java b/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java index 9f4319d857..a4d8eb0908 100644 --- a/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java +++ b/spring-rest/src/test/java/org/baeldung/client/TestRestTemplateBasicLiveTest.java @@ -21,7 +21,7 @@ public class TestRestTemplateBasicLiveTest { private RestTemplate restTemplate; private static final String FOO_RESOURCE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-rest/myfoos"; - private static final String URL_SECURED_BY_AUTHENTICATION = "http://browserspy.dk/password-ok.php"; + private static final String URL_SECURED_BY_AUTHENTICATION = "http://httpbin.org/basic-auth/user/passwd"; private static final String BASE_URL = "http://localhost:" + APPLICATION_PORT + "/spring-rest"; @Before @@ -55,16 +55,16 @@ public class TestRestTemplateBasicLiveTest { @Test public void givenRestTemplateWrapperWithCredentials_whenSendGetForEntity_thenStatusOk() { - TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate, "test", "test"); - ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate, "user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @Test public void givenTestRestTemplateWithCredentials_whenSendGetForEntity_thenStatusOk() { - TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); - ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -72,16 +72,16 @@ public class TestRestTemplateBasicLiveTest { @Test public void givenTestRestTemplateWithBasicAuth_whenSendGetForEntity_thenStatusOk() { TestRestTemplate testRestTemplate = new TestRestTemplate(); - ResponseEntity response = testRestTemplate.withBasicAuth("test", "test"). - getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", String.class); + ResponseEntity response = testRestTemplate.withBasicAuth("user", "passwd"). + getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @Test public void givenTestRestTemplateWithCredentialsAndEnabledCookies_whenSendGetForEntity_thenStatusOk() { - TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test", TestRestTemplate. + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd", TestRestTemplate. HttpClientOption.ENABLE_COOKIES); - ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION + "/1", + ResponseEntity response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class); assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); } @@ -97,18 +97,17 @@ public class TestRestTemplateBasicLiveTest { // POST @Test public void givenService_whenPostForObject_thenCreatedObjectIsReturned() { - TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), "{\"id\":1,\"name\":\"Jim\"}"); final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); - Object response = testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class); - assertTrue(response.toString().contains("Success")); + testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class); } // PUT @Test public void givenService_whenPutForObject_thenCreatedObjectIsReturned() { - TestRestTemplate testRestTemplate = new TestRestTemplate("test", "test"); + TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd"); final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"), "{\"id\":1,\"name\":\"Jim\"}"); final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build(); From 4c84fabd1af0f1d6e2ccf9cd69d3cd1fb39d16d2 Mon Sep 17 00:00:00 2001 From: azrairshad Date: Fri, 31 Mar 2017 10:54:12 -0700 Subject: [PATCH 222/291] Updated ArrayCopy assert statements. (#1540) --- .../baeldung/arraycopy/ArrayCopyUtilTest.java | 65 +++++++------------ 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java index 060f3c3109..2235e55338 100644 --- a/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java +++ b/core-java/src/test/java/com/baeldung/arraycopy/ArrayCopyUtilTest.java @@ -15,14 +15,18 @@ public class ArrayCopyUtilTest { @BeforeClass public static void setup(){ - employees = new Employee[MAX]; - Employee employee; - for(int i = 0; i < MAX; i++) { - employee = new Employee(); - employee.setName("Emp"+i); - employee.setId(i); - employees[i] = employee; - } + createEmployeesArray(); + } + + private static void createEmployeesArray() { + employees = new Employee[MAX]; + Employee employee; + for(int i = 0; i < MAX; i++) { + employee = new Employee(); + employee.setName("Emp"+i); + employee.setId(i); + employees[i] = employee; + } } @Test @@ -32,10 +36,7 @@ public class ArrayCopyUtilTest { System.arraycopy(array, 0, copiedArray, 0, 3); - Assert.assertTrue(array.length == copiedArray.length); - Assert.assertTrue(copiedArray[0] == array[0]); - Assert.assertTrue(copiedArray[1] == array[1]); - Assert.assertTrue(copiedArray[2] == array[2]); + Assert.assertArrayEquals(copiedArray, array); } @Test @@ -70,12 +71,7 @@ public class ArrayCopyUtilTest { int[] copiedArray = Arrays.copyOf(array, newLength); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == array.length); - Assert.assertTrue(copiedArray[0] == array[0]); - Assert.assertTrue(copiedArray[1] == array[1]); - Assert.assertTrue(copiedArray[2] == array[2]); - Assert.assertTrue(copiedArray[3] == array[3]); + Assert.assertArrayEquals(copiedArray, array); array[0] = 9; Assert.assertTrue(copiedArray[0] != array[0]); copiedArray[1] = 12; @@ -86,8 +82,7 @@ public class ArrayCopyUtilTest { public void givenArrayOfNonPrimitiveType_whenCopiedViaArraysCopyOf_thenDoShallowCopy(){ Employee[] copiedArray = Arrays.copyOf(employees, employees.length); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == employees.length); + Assert.assertArrayEquals(copiedArray, employees); employees[0].setName(employees[0].getName()+"_Changed"); //change in employees' element caused change in the copied array Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); @@ -99,12 +94,7 @@ public class ArrayCopyUtilTest { int[] copiedArray = array.clone(); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == array.length); - Assert.assertTrue(copiedArray[0] == array[0]); - Assert.assertTrue(copiedArray[1] == array[1]); - Assert.assertTrue(copiedArray[2] == array[2]); - Assert.assertTrue(copiedArray[3] == array[3]); + Assert.assertArrayEquals(copiedArray, array); array[0] = 9; Assert.assertTrue(copiedArray[0] != array[0]); copiedArray[1] = 12; @@ -115,8 +105,7 @@ public class ArrayCopyUtilTest { public void givenArraysOfNonPrimitiveType_whenCopiedViaArrayClone_thenDoShallowCopy(){ Employee[] copiedArray = employees.clone(); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == employees.length); + Assert.assertArrayEquals(copiedArray, employees);; employees[0].setName(employees[0].getName()+"_Changed"); //change in employees' element changed the copied array Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); @@ -128,29 +117,25 @@ public class ArrayCopyUtilTest { Address[] copiedArray = addresses.clone(); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == addresses.length); addresses[0].setCity(addresses[0].getCity()+"_Changed"); - Assert.assertTrue(copiedArray[0].getCity().equals(addresses[0].getCity())); + Assert.assertArrayEquals(copiedArray, addresses); } @Test public void givenArraysOfSerializableNonPrimitiveType_whenCopiedViaSerializationUtils_thenDoDeepCopy(){ Employee[] copiedArray = SerializationUtils.clone(employees); - - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == employees.length); + employees[0].setName(employees[0].getName()+"_Changed"); //change in employees' element didn't change in the copied array - Assert.assertFalse(copiedArray[0].getName().equals(employees[0].getName())); + Assert.assertFalse( + copiedArray[0].getName().equals(employees[0].getName())); } @Test public void givenArraysOfNonPrimitiveType_whenCopiedViaStream_thenDoShallowCopy(){ Employee[] copiedArray = Arrays.stream(employees).toArray(Employee[]::new); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == employees.length); + Assert.assertArrayEquals(copiedArray, employees); employees[0].setName(employees[0].getName()+"_Changed"); //change in employees' element didn't change in the copied array Assert.assertTrue(copiedArray[0].getName().equals(employees[0].getName())); @@ -162,11 +147,7 @@ public class ArrayCopyUtilTest { String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new); - Assert.assertNotNull(copiedArray); - Assert.assertTrue(copiedArray.length == strArray.length); - Assert.assertTrue(copiedArray[0] == strArray[0]); - Assert.assertTrue(copiedArray[1] == strArray[1]); - Assert.assertTrue(copiedArray[2] == strArray[2]); + Assert.assertArrayEquals(copiedArray, strArray); } private Address[] createAddressArray(){ From 3c334e6b56168d3118d384a9b1529ea7242434b4 Mon Sep 17 00:00:00 2001 From: Danil Kornishev Date: Fri, 31 Mar 2017 16:01:27 -0400 Subject: [PATCH 223/291] Spring State Machine x4 (#1547) * [Fix] Move stateDo onto a separate state * Change tests to spring runner * Add generic params to StateMachine variables --- .../baeldung/spring/statemachine/ForkJoinStateMachineTest.java | 2 +- .../spring/statemachine/HierarchicalStateMachineTest.java | 2 +- .../baeldung/spring/statemachine/JunctionStateMachineTest.java | 2 +- .../com/baeldung/spring/statemachine/StateEnumMachineTest.java | 2 +- .../spring/statemachine/StateMachineIntegrationTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java index 03cb101a9d..0de61da3bd 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; public class ForkJoinStateMachineTest { @Resource - private StateMachine stateMachine; + private StateMachine stateMachine; @Before public void setUp() { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java index 950414bb0e..76105368d8 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java @@ -21,7 +21,7 @@ import static org.junit.Assert.assertEquals; public class HierarchicalStateMachineTest { @Resource - private StateMachine stateMachine; + private StateMachine stateMachine; @Before public void setUp() { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java index 64930162fd..b91e6af5c5 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java @@ -19,7 +19,7 @@ import javax.annotation.Resource; public class JunctionStateMachineTest { @Resource - private StateMachine stateMachine; + private StateMachine stateMachine; @Before public void setUp() { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java index b7cbebe145..cd9e58eb8e 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java @@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue; public class StateEnumMachineTest { @Resource - private StateMachine stateMachine; + private StateMachine stateMachine; @Before public void setUp() { diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java index 8f61d93105..1c1ab58917 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateMachineIntegrationTest.java @@ -22,7 +22,7 @@ import javax.annotation.Resource; public class StateMachineIntegrationTest { @Resource - private StateMachine stateMachine; + private StateMachine stateMachine; @Before public void setUp() { From aaf5a3e7b8cacd6ff7a6523f8a33d3aa4b4b8819 Mon Sep 17 00:00:00 2001 From: gitterjim-I Date: Fri, 31 Mar 2017 21:05:23 +0100 Subject: [PATCH 224/291] Latest review changes: more concise code and suggested refactoring. (#1549) * article Bael-667 initial commit. * Switch to use logging framework for output. * Make code more concise. Refactor as suggested. --- .../FlattenNestedListTest.java | 46 ++++--------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java index fdf4934cb7..b7939d09da 100644 --- a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -1,51 +1,29 @@ package com.baeldung.list.flattennestedlist; -import static org.junit.Assert.assertEquals; +import static java.util.Arrays.asList; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import org.junit.After; -import org.junit.Before; +import org.hamcrest.collection.IsIterableContainingInOrder; import org.junit.Test; public class FlattenNestedListTest { - private List> lol = new ArrayList<>(); - List ls1 = Arrays.asList("one:one", "one:two", "one:three"); - List ls2 = Arrays.asList("two:one", "two:two", "two:three"); - List ls3 = Arrays.asList("three:one", "three:two", "three:three"); - - @Before - public void setup() { - lol.addAll(Arrays.asList(ls1, ls2, ls3)); - } - - @After - public void tearDown() { - lol = null; - } + List> lol = asList(asList("one:one"), asList("two:one", "two:two", "two:three"), asList("three:one", "three:two", "three:three", "three:four")); @Test public void givenString_flattenNestedList1() { List ls = flattenListOfListsImperatively(lol); assertNotNull(ls); - assertTrue(ls.size() == 9); + assertTrue(ls.size() == 8); // assert content - assertEquals(ls.get(0), "one:one"); - assertEquals(ls.get(1), "one:two"); - assertEquals(ls.get(2), "one:three"); - assertEquals(ls.get(3), "two:one"); - assertEquals(ls.get(4), "two:two"); - assertEquals(ls.get(5), "two:three"); - assertEquals(ls.get(6), "three:one"); - assertEquals(ls.get(7), "three:two"); - assertEquals(ls.get(8), "three:three"); + assertThat(ls, IsIterableContainingInOrder.contains("one:one", "two:one", "two:two", "two:three", "three:one", "three:two", "three:three", "three:four")); } @Test @@ -53,17 +31,9 @@ public class FlattenNestedListTest { List ls = flattenListOfListsStream(lol); assertNotNull(ls); - assertTrue(ls.size() == 9); + assertTrue(ls.size() == 8); // assert content - assertEquals(ls.get(0), "one:one"); - assertEquals(ls.get(1), "one:two"); - assertEquals(ls.get(2), "one:three"); - assertEquals(ls.get(3), "two:one"); - assertEquals(ls.get(4), "two:two"); - assertEquals(ls.get(5), "two:three"); - assertEquals(ls.get(6), "three:one"); - assertEquals(ls.get(7), "three:two"); - assertEquals(ls.get(8), "three:three"); + assertThat(ls, IsIterableContainingInOrder.contains("one:one", "two:one", "two:two", "two:three", "three:one", "three:two", "three:three", "three:four")); } public List flattenListOfListsImperatively(List> list) { From cc0c7d54a9b250c00d9efcfaac4119fe85f9cb72 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 1 Apr 2017 08:18:52 +0200 Subject: [PATCH 225/291] Enable hbase (#1545) --- hbase/pom.xml | 1 + pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hbase/pom.xml b/hbase/pom.xml index 2382e47af2..9d523abf1a 100644 --- a/hbase/pom.xml +++ b/hbase/pom.xml @@ -33,6 +33,7 @@ org.apache.hbase hbase ${hbase.version} + pom junit diff --git a/pom.xml b/pom.xml index 6b4511e45b..b26ada6f24 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ handling-spring-static-resources hazelcast - + hbase httpclient hystrix From 4b98413c4ad1f82bb9d95aeeec780dc2bd47bad1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Sat, 1 Apr 2017 07:53:56 +0100 Subject: [PATCH 226/291] Moved AOP module and removed Spring Boot starter (#1506) * Moved AOP module and removed Spring Boot starter * Fixed accidentally committed git message * Fixed pom --- spring-aop/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index 1c3b5bdccd..bd86839742 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -15,11 +15,6 @@ - - org.springframework.boot - spring-boot-starter - - org.springframework.boot spring-boot-starter-aop @@ -28,7 +23,6 @@ org.springframework.boot spring-boot-starter-test - test From 760692b8eb5e66ef20be5c183ab0e00e98c470df Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 1 Apr 2017 09:06:59 +0200 Subject: [PATCH 227/291] Build time optimization (#1553) * Add integration tests * Optimize build --- apache-poi/.gitignore | 2 ++ jee7/pom.xml | 2 +- .../ScheduleTimerBeanIntegrationTest.java | 36 +++++++++++-------- jooq/src/test/java/com/baeldung/JOOLTest.java | 3 -- pom.xml | 13 +++++++ querydsl/pom.xml | 1 - ...Test.java => QueryDSLIntegrationTest.java} | 20 +++++------ rxjava/pom.xml | 13 +++++++ ...xJavaBackpressureLongRunningUnitTest.java} | 2 +- ... => MessageControllerIntegrationTest.java} | 5 +-- spring-jooq/pom.xml | 2 +- 11 files changed, 66 insertions(+), 33 deletions(-) rename querydsl/src/test/java/org/baeldung/querydsl/intro/{QueryDSLTest.java => QueryDSLIntegrationTest.java} (99%) rename rxjava/src/test/java/com/baeldung/rxjava/{RxJavaBackpressureTest.java => RxJavaBackpressureLongRunningUnitTest.java} (98%) rename spring-amqp-simple/src/test/java/com/baeldung/springamqpsimple/{MessageControllerTest.java => MessageControllerIntegrationTest.java} (88%) diff --git a/apache-poi/.gitignore b/apache-poi/.gitignore index e05054868c..9552c1e63d 100644 --- a/apache-poi/.gitignore +++ b/apache-poi/.gitignore @@ -1 +1,3 @@ *.docx +temp.xls +temp.xlsx diff --git a/jee7/pom.xml b/jee7/pom.xml index f275f56d58..26d433df78 100644 --- a/jee7/pom.xml +++ b/jee7/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.baeldung - jee7schedule + jee7 1.0-SNAPSHOT JavaEE 7 Arquillian Archetype Sample war diff --git a/jee7/src/test/java/com/baeldung/timer/ScheduleTimerBeanIntegrationTest.java b/jee7/src/test/java/com/baeldung/timer/ScheduleTimerBeanIntegrationTest.java index c3c5ad44de..580edade77 100644 --- a/jee7/src/test/java/com/baeldung/timer/ScheduleTimerBeanIntegrationTest.java +++ b/jee7/src/test/java/com/baeldung/timer/ScheduleTimerBeanIntegrationTest.java @@ -19,25 +19,27 @@ import static com.jayway.awaitility.Awaitility.to; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; - @RunWith(Arquillian.class) public class ScheduleTimerBeanIntegrationTest { - final static long TIMEOUT = 5000l; - final static long TOLERANCE = 1000l; + private final static long TIMEOUT = 5000l; + private final static long TOLERANCE = 1000l; - @Inject - TimerEventListener timerEventListener; + @Inject TimerEventListener timerEventListener; @Deployment public static WebArchive deploy() { - File[] jars = Maven.resolver().loadPomFromFile("pom.xml") - .resolve("com.jayway.awaitility:awaitility") - .withTransitivity().asFile(); + File[] jars = Maven + .resolver() + .loadPomFromFile("pom.xml") + .resolve("com.jayway.awaitility:awaitility") + .withTransitivity() + .asFile(); - return ShrinkWrap.create(WebArchive.class) - .addAsLibraries(jars) - .addClasses(WithinWindowMatcher.class, TimerEvent.class, TimerEventListener.class, ScheduleTimerBean.class); + return ShrinkWrap + .create(WebArchive.class) + .addAsLibraries(jars) + .addClasses(WithinWindowMatcher.class, TimerEvent.class, TimerEventListener.class, ScheduleTimerBean.class); } @Test @@ -46,9 +48,15 @@ public class ScheduleTimerBeanIntegrationTest { Awaitility.setDefaultTimeout(30, TimeUnit.SECONDS); await().untilCall(to(timerEventListener.getEvents()).size(), equalTo(3)); - TimerEvent firstEvent = timerEventListener.getEvents().get(0); - TimerEvent secondEvent = timerEventListener.getEvents().get(1); - TimerEvent thirdEvent = timerEventListener.getEvents().get(2); + TimerEvent firstEvent = timerEventListener + .getEvents() + .get(0); + TimerEvent secondEvent = timerEventListener + .getEvents() + .get(1); + TimerEvent thirdEvent = timerEventListener + .getEvents() + .get(2); long delay = secondEvent.getTime() - firstEvent.getTime(); assertThat(delay, Matchers.is(WithinWindowMatcher.withinWindow(TIMEOUT, TOLERANCE))); diff --git a/jooq/src/test/java/com/baeldung/JOOLTest.java b/jooq/src/test/java/com/baeldung/JOOLTest.java index 13bf1a3ec3..a0d5f4037f 100644 --- a/jooq/src/test/java/com/baeldung/JOOLTest.java +++ b/jooq/src/test/java/com/baeldung/JOOLTest.java @@ -1,12 +1,9 @@ package com.baeldung; - -import junit.framework.Assert; import org.jooq.lambda.Seq; import org.jooq.lambda.Unchecked; import org.jooq.lambda.function.Function1; import org.jooq.lambda.function.Function2; -import org.jooq.lambda.tuple.Tuple; import org.jooq.lambda.tuple.Tuple2; import org.jooq.lambda.tuple.Tuple3; import org.jooq.lambda.tuple.Tuple4; diff --git a/pom.xml b/pom.xml index b26ada6f24..76f7247f51 100644 --- a/pom.xml +++ b/pom.xml @@ -214,6 +214,7 @@ vertx spring-data-gemfire + @@ -226,6 +227,18 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LongRunningUnitTest.java + **/*ManualTest.java + + true + + @@ -280,6 +286,7 @@ 4.3.4.RELEASE 4.2.0.RELEASE 1.1.5.RELEASE + 1.2.0.RELEASE 5.2.5.Final diff --git a/spring-all/src/main/java/org/baeldung/shell/Main.java b/spring-all/src/main/java/org/baeldung/shell/Main.java new file mode 100644 index 0000000000..3d9f7a5860 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/Main.java @@ -0,0 +1,10 @@ +package org.baeldung.shell; + +import java.io.IOException; +import org.springframework.shell.Bootstrap; + +public class Main { + public static void main(String[] args) throws IOException { + Bootstrap.main(args); + } +} diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java new file mode 100644 index 0000000000..df7a48cd32 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java @@ -0,0 +1,34 @@ +package org.baeldung.shell.simple; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.shell.plugin.support.DefaultBannerProvider; +import org.springframework.shell.support.util.OsUtils; +import org.springframework.stereotype.Component; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleBannerProvider extends DefaultBannerProvider { + + public String getBanner() { + StringBuffer buf = new StringBuffer(); + buf.append("=======================================").append(OsUtils.LINE_SEPARATOR); + buf.append("* Baeldung Shell *").append(OsUtils.LINE_SEPARATOR); + buf.append("=======================================").append(OsUtils.LINE_SEPARATOR); + buf.append("Version:").append(this.getVersion()); + return buf.toString(); + } + + public String getVersion() { + return "1.0.1"; + } + + public String getWelcomeMessage() { + return "Welcome to Baeldung CLI"; + } + + @Override + public String getProviderName() { + return "Baeldung Banner"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java new file mode 100644 index 0000000000..0bbc62cf2c --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java @@ -0,0 +1,81 @@ +package org.baeldung.shell.simple; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.springframework.shell.Bootstrap; +import org.springframework.shell.core.CommandMarker; +import org.springframework.shell.core.annotation.CliAvailabilityIndicator; +import org.springframework.shell.core.annotation.CliCommand; +import org.springframework.shell.core.annotation.CliOption; +import org.springframework.stereotype.Component; + +@Component +public class SimpleCLI implements CommandMarker { + + private String getContentsOfUrlAsString(URL url) { + StringBuilder sb = new StringBuilder(); + try { + try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + sb.append(inputLine); + } + } + } catch (IOException ex) { + sb.append("ERROR"); + } + return sb.toString(); + } + + @CliCommand( + value = {"web-get", "wg"}, + help = "Displays the contents of a URL." + ) + public String webGet( + @CliOption( + key = {"", "url"}, + help = "URL whose contents will be displayed." + ) URL url) { + return getContentsOfUrlAsString(url); + } + + @CliCommand( + value = {"web-save", "ws"}, + help = "Saves the contents of a URL.") + public String webSave( + @CliOption(key = {"", "url"}, help = "URL whose contents will be saved.") URL url, + @CliOption(key = {"out", "file"}, mandatory = true, help = "The name of the file.") String file) { + String contents = getContentsOfUrlAsString(url); + try (PrintWriter out = new PrintWriter(file)) { + out.write(contents); + } catch (FileNotFoundException ex) { + //Ignore + } + return "Done."; + } + + private boolean adminEnableExecuted = false; + + @CliAvailabilityIndicator(value = {"web-save"}) + public boolean isAdminEnabled() { + return adminEnableExecuted; + } + + @CliCommand(value = "admin-enable") + public String adminEnable() { + adminEnableExecuted = true; + return "Admin commands enabled."; + } + + @CliCommand(value = "admin-disable") + public String adminDisable() { + adminEnableExecuted = false; + return "Admin commands disabled."; + } +} diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java new file mode 100644 index 0000000000..cef53adc69 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java @@ -0,0 +1,22 @@ +package org.baeldung.shell.simple; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider; +import org.springframework.stereotype.Component; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleHistoryFileNameProvider extends DefaultHistoryFileNameProvider { + + @Override + public String getHistoryFileName() { + return "baeldung-shell.log"; + } + + @Override + public String getProviderName() { + return "Baeldung History"; + } + +} diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java new file mode 100644 index 0000000000..9a84954e05 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java @@ -0,0 +1,21 @@ +package org.baeldung.shell.simple; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.shell.plugin.support.DefaultPromptProvider; +import org.springframework.stereotype.Component; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimplePromptProvider extends DefaultPromptProvider { + + @Override + public String getPrompt() { + return "baeldung-shell>"; + } + + @Override + public String getProviderName() { + return "Baeldung Prompt"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java new file mode 100644 index 0000000000..66bab5c488 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java @@ -0,0 +1,35 @@ +package org.baeldung.shell.simple; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import org.springframework.shell.core.Completion; +import org.springframework.shell.core.Converter; +import org.springframework.shell.core.MethodTarget; +import org.springframework.stereotype.Component; + +@Component +public class SimpleURLConverter implements Converter { + + @Override + public URL convertFromText(String value, Class requiredType, String optionContext) { + try { + return new URL(value); + } catch (MalformedURLException ex) { + //Ignore + } + return null; + } + + @Override + public boolean getAllPossibleValues(List completions, Class requiredType, + String existingData, String optionContext, MethodTarget target) { + return false; + } + + @Override + public boolean supports(Class requiredType, String optionContext) { + return URL.class.isAssignableFrom(requiredType); + } + +} diff --git a/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml b/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml new file mode 100644 index 0000000000..aea1a663c1 --- /dev/null +++ b/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java b/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java new file mode 100644 index 0000000000..0353083943 --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java @@ -0,0 +1,86 @@ +package org.baeldung.shell.simple; + +import java.io.File; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.shell.Bootstrap; +import org.springframework.shell.core.CommandResult; +import org.springframework.shell.core.JLineShellComponent; + +public class SimpleCLIUnitTest { + + static JLineShellComponent shell; + + @BeforeClass + public static void startUp() throws InterruptedException { + Bootstrap bootstrap = new Bootstrap(); + shell = bootstrap.getJLineShellComponent(); + } + + @AfterClass + public static void shutdown() { + shell.stop(); + } + + public static JLineShellComponent getShell() { + return shell; + } + + @Test + public void givenCommandConfig_whenExecutingWebGetCommand_thenCorrectResult() { + + CommandResult resultWebSave = shell.executeCommand("web-get --url https://www.google.com"); + + Assert.assertTrue(resultWebSave.isSuccess()); + } + + @Test + public void givenCommandConfig_whenExecutingWebSaveCommand_thenCorrectResult() { + + shell.executeCommand("admin-enable"); + CommandResult result = shell.executeCommand("web-save --url https://www.google.com --out contents.txt"); + + Assert.assertArrayEquals( + new boolean[]{ + result.isSuccess(), + new File("contents.txt").exists()}, + new boolean[]{true, true}); + } + + @Test + public void givenCommandConfig_whenAdminEnableCommandExecuted_thenCorrectAvailability() { + + CommandResult resultAdminDisable = shell.executeCommand("admin-disable"); + CommandResult resultWebSaveUnavailable = shell.executeCommand("web-save --url https://www.google.com --out contents.txt"); + CommandResult resultAdminEnable = shell.executeCommand("admin-enable"); + CommandResult resultWebSaveAvailable = shell.executeCommand("web-save --url https://www.google.com --out contents.txt"); + + Assert.assertArrayEquals( + new boolean[]{ + resultAdminDisable.isSuccess(), + resultWebSaveUnavailable.isSuccess(), + resultAdminEnable.isSuccess(), + resultWebSaveAvailable.isSuccess()}, + new boolean[]{true, false, true, true}); + } + + @Test + public void givenCommandConfig_whenWebSaveCommandExecutedNoOutArgument_thenError() { + + shell.executeCommand("admin-enable"); + CommandResult resultWebSave = shell.executeCommand("web-save --url https://www.google.com"); + + Assert.assertEquals(resultWebSave.isSuccess(), false); + } + + @Test + public void givenCommandConfig_whenExecutingWebGetCommandWithDefaultArgument_thenCorrectResult() { + + CommandResult result = shell.executeCommand("web-get https://www.google.com"); + + Assert.assertEquals(result.isSuccess(), true); + } + +} From 077d745b8d2bb33a48d82d14cdf378bc7eca1eab Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Sat, 1 Apr 2017 23:02:19 +0200 Subject: [PATCH 234/291] BAEL-75 - Spring Boot Audit Support (#1561) Rework to avoid the separate spring-boot-auditing module by moving the code to the spring-security-core module --- spring-boot-auditing/.gitignore | 6 - spring-boot-auditing/pom.xml | 198 ------------------ .../main/java/org/baeldung/Application.java | 13 -- .../src/main/java/org/baeldung/MvcConfig.java | 18 -- .../java/org/baeldung/WebSecurityConfig.java | 34 --- .../src/main/resources/application.properties | 1 - .../src/main/resources/logback.xml | 14 -- .../src/main/resources/templates/hello.html | 13 -- .../src/main/resources/templates/home.html | 11 - .../src/main/resources/templates/login.html | 20 -- spring-security-core/pom.xml | 4 + ...temptedPathAuthorizationAuditListener.java | 0 .../auditing/LoginAttemptsLogger.java | 8 +- .../baeldung/config/WebSecurityConfig.java | 5 +- 14 files changed, 12 insertions(+), 333 deletions(-) delete mode 100644 spring-boot-auditing/.gitignore delete mode 100644 spring-boot-auditing/pom.xml delete mode 100755 spring-boot-auditing/src/main/java/org/baeldung/Application.java delete mode 100755 spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java delete mode 100755 spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java delete mode 100644 spring-boot-auditing/src/main/resources/application.properties delete mode 100644 spring-boot-auditing/src/main/resources/logback.xml delete mode 100755 spring-boot-auditing/src/main/resources/templates/hello.html delete mode 100755 spring-boot-auditing/src/main/resources/templates/home.html delete mode 100755 spring-boot-auditing/src/main/resources/templates/login.html rename {spring-boot-auditing => spring-security-core}/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java (100%) rename {spring-boot-auditing => spring-security-core}/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java (72%) diff --git a/spring-boot-auditing/.gitignore b/spring-boot-auditing/.gitignore deleted file mode 100644 index 31ce405488..0000000000 --- a/spring-boot-auditing/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/target/ -.settings/ -.classpath -.project -*.iml -.idea \ No newline at end of file diff --git a/spring-boot-auditing/pom.xml b/spring-boot-auditing/pom.xml deleted file mode 100644 index 0afbe0becc..0000000000 --- a/spring-boot-auditing/pom.xml +++ /dev/null @@ -1,198 +0,0 @@ - - 4.0.0 - com.baeldung - spring-boot-auditing - 0.0.1-SNAPSHOT - war - spring-boot-auditing - This is simple boot application for Spring boot auditing test - - - - org.springframework.boot - spring-boot-starter-parent - 1.5.2.RELEASE - - - - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.boot - spring-boot-starter-security - - - - io.dropwizard.metrics - metrics-core - - - - com.h2database - h2 - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-starter - - - com.jayway.jsonpath - json-path - test - - - org.springframework.boot - spring-boot-starter-mail - - - org.subethamail - subethasmtp - ${subethasmtp.version} - test - - - - org.webjars - bootstrap - ${bootstrap.version} - - - org.webjars - jquery - ${jquery.version} - - - - org.apache.tomcat - tomcat-servlet-api - ${tomee-servlet-api.version} - provided - - - - - - spring-boot - - - src/main/resources - true - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - org.apache.maven.plugins - maven-war-plugin - - - - pl.project13.maven - git-commit-id-plugin - ${git-commit-id-plugin.version} - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/*IntegrationTest.java - **/*LiveTest.java - - - - - - - - - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - - - - - UTF-8 - 1.8 - 4.3.7.RELEASE - 2.2.1 - 3.1.1 - 3.3.7-1 - 3.1.7 - 8.5.11 - - - diff --git a/spring-boot-auditing/src/main/java/org/baeldung/Application.java b/spring-boot-auditing/src/main/java/org/baeldung/Application.java deleted file mode 100755 index bf7b7bd1a6..0000000000 --- a/spring-boot-auditing/src/main/java/org/baeldung/Application.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.baeldung; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) throws Throwable { - SpringApplication.run(Application.class, args); - } - -} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java b/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java deleted file mode 100755 index fecb8c5c0b..0000000000 --- a/spring-boot-auditing/src/main/java/org/baeldung/MvcConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.baeldung; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -@Configuration -public class MvcConfig extends WebMvcConfigurerAdapter { - - @Override - public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/home").setViewName("home"); - registry.addViewController("/").setViewName("home"); - registry.addViewController("/hello").setViewName("hello"); - registry.addViewController("/login").setViewName("login"); - } - -} diff --git a/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java b/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java deleted file mode 100755 index 9339d8e804..0000000000 --- a/spring-boot-auditing/src/main/java/org/baeldung/WebSecurityConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.baeldung; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; - -@Configuration -@EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .antMatchers("/", "/home").permitAll() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/login") - .permitAll() - .and() - .logout() - .permitAll(); - } - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER", "ACTUATOR"); - } -} diff --git a/spring-boot-auditing/src/main/resources/application.properties b/spring-boot-auditing/src/main/resources/application.properties deleted file mode 100644 index cf09473b60..0000000000 --- a/spring-boot-auditing/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -logging.level.org.springframework=INFO \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/logback.xml b/spring-boot-auditing/src/main/resources/logback.xml deleted file mode 100644 index 78913ee76f..0000000000 --- a/spring-boot-auditing/src/main/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - web - %date [%thread] %-5level %logger{36} - %message%n - - - - - - - - - \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/hello.html b/spring-boot-auditing/src/main/resources/templates/hello.html deleted file mode 100755 index 46feef7e2c..0000000000 --- a/spring-boot-auditing/src/main/resources/templates/hello.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Hello World! - - -

Hello [[${#httpServletRequest.remoteUser}]]!

-
- -
- - \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/home.html b/spring-boot-auditing/src/main/resources/templates/home.html deleted file mode 100755 index fe4e8b337e..0000000000 --- a/spring-boot-auditing/src/main/resources/templates/home.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Spring Security Example - - -

Welcome!

- -

Click here to see a greeting.

- - \ No newline at end of file diff --git a/spring-boot-auditing/src/main/resources/templates/login.html b/spring-boot-auditing/src/main/resources/templates/login.html deleted file mode 100755 index a1785313f5..0000000000 --- a/spring-boot-auditing/src/main/resources/templates/login.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Spring Security Example - - -
- Invalid username and password. -
-
- You have been logged out. -
-
-
-
-
-
- - \ No newline at end of file diff --git a/spring-security-core/pom.xml b/spring-security-core/pom.xml index a8ffce84b7..971f5a9d0f 100644 --- a/spring-security-core/pom.xml +++ b/spring-security-core/pom.xml @@ -32,6 +32,10 @@ org.springframework.boot spring-boot-starter-thymeleaf
+ + org.springframework.boot + spring-boot-starter-actuator + com.h2database h2 diff --git a/spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java b/spring-security-core/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java similarity index 100% rename from spring-boot-auditing/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java rename to spring-security-core/src/main/java/org/baeldung/auditing/ExposeAttemptedPathAuthorizationAuditListener.java diff --git a/spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java b/spring-security-core/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java similarity index 72% rename from spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java rename to spring-security-core/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java index 5be8cebfd3..bf0781bced 100644 --- a/spring-boot-auditing/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java +++ b/spring-security-core/src/main/java/org/baeldung/auditing/LoginAttemptsLogger.java @@ -15,11 +15,11 @@ public class LoginAttemptsLogger { @EventListener public void auditEventHappened(AuditApplicationEvent auditApplicationEvent) { AuditEvent auditEvent = auditApplicationEvent.getAuditEvent(); - LOGGER.debug("Principal " + auditEvent.getPrincipal() + " - " + auditEvent.getType()); + LOGGER.info("Principal " + auditEvent.getPrincipal() + " - " + auditEvent.getType()); WebAuthenticationDetails details = (WebAuthenticationDetails) auditEvent.getData().get("details"); - LOGGER.debug(" Remote IP address: " + details.getRemoteAddress()); - LOGGER.debug(" Session Id: " + details.getSessionId()); - LOGGER.debug(" Request URL: " + auditEvent.getData().get("requestUrl")); + LOGGER.info(" Remote IP address: " + details.getRemoteAddress()); + LOGGER.info(" Session Id: " + details.getSessionId()); + LOGGER.info(" Request URL: " + auditEvent.getData().get("requestUrl")); } } diff --git a/spring-security-core/src/main/java/org/baeldung/config/WebSecurityConfig.java b/spring-security-core/src/main/java/org/baeldung/config/WebSecurityConfig.java index 5441dac7f7..0b6cd34f3e 100644 --- a/spring-security-core/src/main/java/org/baeldung/config/WebSecurityConfig.java +++ b/spring-security-core/src/main/java/org/baeldung/config/WebSecurityConfig.java @@ -20,6 +20,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("jim").password("jim").roles("USER").and().withUser("pam").password("pam").roles("USER").and().withUser("michael").password("michael").roles("MANAGER"); + auth.inMemoryAuthentication() + .withUser("jim").password("jim").roles("USER", "ACTUATOR") + .and().withUser("pam").password("pam").roles("USER") + .and().withUser("michael").password("michael").roles("MANAGER"); } } From 8fc519538dff4ddb6ed83164bdd8759759435120 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Sun, 2 Apr 2017 10:07:37 +0200 Subject: [PATCH 235/291] Bael 112 validator upgrade (#1567) * BAEL-112 - upgrading hibernate validator * BAEL-112 - upgrading hibernate validator --- spring-mvc-java/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index 0f6dbfbd98..dcf740b22b 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -176,7 +176,7 @@ org.hibernate hibernate-validator - 5.1.2.Final + ${hibernate-validator.version} javax.el @@ -370,7 +370,7 @@ 1.1.7 - 5.3.3.Final + 5.4.1.Final 3.1.0 1.2 From b4b5f79ce1ca5cb0f78a2cb8ae15d4dc920f97ee Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Sun, 2 Apr 2017 03:08:13 -0500 Subject: [PATCH 236/291] BAEL-666: README (#1563) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README --- jackson/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/jackson/README.md b/jackson/README.md index d9faa377f1..5bc16e66b7 100644 --- a/jackson/README.md +++ b/jackson/README.md @@ -26,3 +26,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Inheritance with Jackson](http://www.baeldung.com/jackson-inheritance) - [Guide to @JsonFormat in Jackson](http://www.baeldung.com/jackson-jsonformat) - [A Guide to Optional with Jackson](http://www.baeldung.com/jackson-optional) +- [Map Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-map) From d85f1640d70ab55243d4677c17bb02c88443954c Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Sun, 2 Apr 2017 16:35:58 +0530 Subject: [PATCH 237/291] BAEL-716 Junit vs testng improvement --- .../baeldung/junit4vstestng/SortedTests.java | 25 +++++++++++++++++++ .../test/java/baeldung/com/PriorityTest.java | 23 +++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java create mode 100644 testng/src/test/java/baeldung/com/PriorityTest.java diff --git a/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java b/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java new file mode 100644 index 0000000000..1fa4a4e61b --- /dev/null +++ b/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java @@ -0,0 +1,25 @@ +package com.baeldung.junit4vstestng; + +import static org.junit.Assert.assertTrue; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SortedTests { + + @Test + public void a_givenString_whenChangedtoInt_thenTrue(){ + assertTrue( + Integer.valueOf("10") instanceof Integer); + } + + @Test + public void b_givenInt_whenChangedtoString_thenTrue(){ + assertTrue( + String.valueOf(10) instanceof String); + } + +} diff --git a/testng/src/test/java/baeldung/com/PriorityTest.java b/testng/src/test/java/baeldung/com/PriorityTest.java new file mode 100644 index 0000000000..34f2d6fe47 --- /dev/null +++ b/testng/src/test/java/baeldung/com/PriorityTest.java @@ -0,0 +1,23 @@ +package baeldung.com; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class PriorityTest { + + private String testString = "10"; + private int testInt = 23; + + @Test(priority = 1) + public void givenString_whenChangedToInt_thenCorrect() { + Assert.assertTrue( + Integer.valueOf(testString) instanceof Integer); + } + + @Test(priority = 2) + public void givenInt_whenChangedToString_thenCorrect() { + Assert.assertTrue( + String.valueOf(testInt) instanceof String); + } + +} From 8e060b9aafb5c172f1b6da6a9b0df8f1dfed0531 Mon Sep 17 00:00:00 2001 From: Nikhil Khatwani Date: Sun, 2 Apr 2017 20:18:21 +0530 Subject: [PATCH 238/291] Bael 711 guide to microservices using lagom framework v2 (#1573) * BAEL_711_Guide_to_Microservices_using_lagom_framework Changes * BAEL_711_Guide_to_Microservices_using_lagom_framework_v2 * BAEL_711_Guide_to_Microservices_using_lagom-Review Comments * Corrected scala version --- lagom/build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lagom/build.sbt b/lagom/build.sbt index 064d67468e..06927e3301 100644 --- a/lagom/build.sbt +++ b/lagom/build.sbt @@ -1,7 +1,7 @@ organization in ThisBuild := "org.baeldung" // the Scala version that will be used for cross-compiled libraries -scalaVersion in ThisBuild := "2.11.7" +scalaVersion in ThisBuild := "2.11.8" lagomKafkaEnabled in ThisBuild := false @@ -38,4 +38,4 @@ lazy val weatherImpl = project("weather-impl") ) .dependsOn(weatherApi) -def project(id: String) = Project(id, base = file(id)) \ No newline at end of file +def project(id: String) = Project(id, base = file(id)) From c3b73c5e568a703a482727574d5bf355ba942933 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Sun, 2 Apr 2017 15:50:00 +0100 Subject: [PATCH 239/291] Bael 627 (#1431) * Initial commit * Spock examples * Changed Spock Version --- groovy-spock/pom.xml | 47 ++++ .../src/test/groovy/FirstSpecification.groovy | 89 +++++++ groovy-spock/src/test/groovy/Notifier.groovy | 3 + .../src/test/groovy/PaymentGateway.groovy | 3 + pom.xml | 1 + .../spring-custom-aop/.gitignore | 4 + spring-custom-aop/spring-custom-aop/README.MD | 13 + spring-custom-aop/spring-custom-aop/pom.xml | 224 ++++++++++++++++++ .../SpringBootAnnotatedApp.java | 25 ++ .../SpringBootPlainApp.java | 13 + .../components/AttrListener.java | 23 ++ .../components/EchoServlet.java | 29 +++ .../components/HelloFilter.java | 32 +++ .../components/HelloServlet.java | 32 +++ .../com/baeldung/git/CommitIdApplication.java | 23 ++ .../baeldung/git/CommitInfoController.java | 30 +++ .../src/main/java/com/baeldung/git/README.md | 2 + .../InternationalizationApp.java | 15 ++ .../config/MvcConfig.java | 38 +++ .../config/PageController.java | 14 ++ .../src/main/java/com/baeldung/intro/App.java | 13 + .../intro/controller/HomeController.java | 18 ++ .../baeldung/servlets/ApplicationMain.java | 19 ++ .../configuration/WebAppInitializer.java | 32 +++ .../configuration/WebMvcConfigure.java | 39 +++ .../baeldung/servlets/props/Constants.java | 20 ++ .../servlets/props/PropertyLoader.java | 27 +++ .../servlets/props/PropertySourcesLoader.java | 23 ++ .../servlets/GenericCustomServlet.java | 18 ++ .../servlets/javaee/AnnotationServlet.java | 20 ++ .../servlets/javaee/EEWebXmlServlet.java | 20 ++ .../SpringRegistrationBeanServlet.java | 17 ++ .../embedded/EmbeddedTomcatExample.java | 16 ++ .../java/com/baeldung/utils/Application.java | 18 ++ .../utils/controller/UtilsController.java | 49 ++++ .../com/baeldung/webjar/TestController.java | 15 ++ .../webjar/WebjarsdemoApplication.java | 13 + .../main/java/org/baeldung/Application.java | 13 + .../org/baeldung/boot/DemoApplication.java | 14 ++ .../baeldung/boot/components/FooService.java | 21 ++ .../boot/exceptions/CommonException.java | 13 + .../boot/exceptions/FooNotFoundException.java | 13 + .../java/org/baeldung/boot/model/Foo.java | 46 ++++ .../boot/repository/FooRepository.java | 8 + .../baeldung/boot/service/FooController.java | 26 ++ .../java/org/baeldung/client/Details.java | 32 +++ .../baeldung/client/DetailsServiceClient.java | 20 ++ .../common/error/MyCustomErrorController.java | 24 ++ .../SpringHelloServletRegistrationBean.java | 15 ++ .../error/controller/ErrorController.java | 22 ++ .../MyServletContainerCustomizationBean.java | 25 ++ .../ExecutorServiceExitCodeGenerator.java | 29 +++ .../java/org/baeldung/config/WebConfig.java | 17 ++ .../controller/GenericEntityController.java | 59 +++++ .../controller/servlet/HelloWorldServlet.java | 43 ++++ .../servlet/SpringHelloWorldServlet.java | 43 ++++ .../StringToEnumConverterFactory.java | 27 +++ .../StringToLocalDateTimeConverter.java | 16 ++ .../org/baeldung/domain/GenericEntity.java | 42 ++++ .../main/java/org/baeldung/domain/Modes.java | 6 + .../baeldung/endpoints/CustomEndpoint.java | 35 +++ .../org/baeldung/endpoints/ListEndpoints.java | 23 ++ .../org/baeldung/endpoints/MyHealthCheck.java | 22 ++ .../baeldung/main/SpringBootApplication.java | 68 ++++++ .../monitor/jmx/MonitoringConfig.java | 21 ++ .../repository/GenericEntityRepository.java | 7 + .../org/baeldung/service/LoginService.java | 5 + .../baeldung/service/LoginServiceImpl.java | 29 +++ .../session/exception/Application.java | 23 ++ .../exception/repository/FooRepository.java | 10 + .../repository/FooRepositoryImpl.java | 25 ++ .../HeaderVersionArgumentResolver.java | 26 ++ .../org/baeldung/web/resolver/Version.java | 11 + .../src/main/resources/application.properties | 43 ++++ .../src/main/resources/banner.txt | 14 ++ .../src/main/resources/custom.properties | 4 + .../src/main/resources/demo.properties | 6 + .../src/main/resources/logback.xml | 14 ++ .../src/main/resources/messages.properties | 4 + .../src/main/resources/messages_fr.properties | 4 + .../src/main/resources/public/error/404.html | 8 + .../src/main/resources/templates/index.html | 19 ++ .../resources/templates/international.html | 29 +++ .../src/main/resources/templates/other.html | 16 ++ .../src/main/resources/templates/utils.html | 23 ++ .../src/main/webapp/WEB-INF/context.xml | 12 + .../src/main/webapp/WEB-INF/dispatcher.xml | 16 ++ .../src/main/webapp/WEB-INF/web.xml | 40 ++++ .../src/main/webapp/annotationservlet.jsp | 1 + .../src/main/webapp/index.jsp | 1 + ...otWithServletComponentIntegrationTest.java | 65 +++++ ...ithoutServletComponentIntegrationTest.java | 50 ++++ .../baeldung/git/CommitIdIntegrationTest.java | 41 ++++ .../java/com/baeldung/intro/AppLiveTest.java | 41 ++++ .../baeldung/utils/UtilsControllerTest.java | 41 ++++ ...WebjarsdemoApplicationIntegrationTest.java | 18 ++ .../SpringBootApplicationIntegrationTest.java | 66 ++++++ .../SpringBootJPAIntegrationTest.java | 27 +++ .../SpringBootMailIntegrationTest.java | 81 +++++++ .../boot/ApplicationIntegrationTest.java | 17 ++ .../boot/DemoApplicationIntegrationTest.java | 17 ++ .../org/baeldung/boot/FooComponentTests.java | 70 ++++++ .../org/baeldung/boot/FooIntegrationTest.java | 43 ++++ .../java/org/baeldung/boot/FooJPATest.java | 34 +++ .../java/org/baeldung/boot/FooJsonTest.java | 35 +++ .../FooRepositoryIntegrationTest.java | 34 +++ .../HibernateSessionIntegrationTest.java | 32 +++ .../NoHibernateSessionIntegrationTest.java | 21 ++ .../DetailsServiceClientIntegrationTest.java | 46 ++++ .../src/test/resources/application.properties | 5 + .../resources/exception-hibernate.properties | 2 + .../src/test/resources/exception.properties | 6 + .../src/test/resources/import.sql | 1 + .../resources/org/baeldung/boot/expected.json | 4 + 114 files changed, 2967 insertions(+) create mode 100644 groovy-spock/pom.xml create mode 100644 groovy-spock/src/test/groovy/FirstSpecification.groovy create mode 100644 groovy-spock/src/test/groovy/Notifier.groovy create mode 100644 groovy-spock/src/test/groovy/PaymentGateway.groovy create mode 100644 spring-custom-aop/spring-custom-aop/.gitignore create mode 100644 spring-custom-aop/spring-custom-aop/README.MD create mode 100644 spring-custom-aop/spring-custom-aop/pom.xml create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootAnnotatedApp.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootPlainApp.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/AttrListener.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/EchoServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloFilter.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitIdApplication.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitInfoController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/README.md create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/InternationalizationApp.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/MvcConfig.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/PageController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/App.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/controller/HomeController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/ApplicationMain.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/Constants.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertyLoader.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/Application.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/controller/UtilsController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/TestController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/Application.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/DemoApplication.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/components/FooService.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/CommonException.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/model/Foo.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/repository/FooRepository.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/service/FooController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/Details.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/DetailsServiceClient.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/MyCustomErrorController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/SpringHelloServletRegistrationBean.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/controller/ErrorController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/properties/MyServletContainerCustomizationBean.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/resources/ExecutorServiceExitCodeGenerator.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/config/WebConfig.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/GenericEntityController.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/HelloWorldServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/SpringHelloWorldServlet.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToEnumConverterFactory.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToLocalDateTimeConverter.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/GenericEntity.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/Modes.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/CustomEndpoint.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/ListEndpoints.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/MyHealthCheck.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/main/SpringBootApplication.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/monitor/jmx/MonitoringConfig.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/repository/GenericEntityRepository.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginService.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginServiceImpl.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/Application.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepository.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepositoryImpl.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/HeaderVersionArgumentResolver.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/Version.java create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/application.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/banner.txt create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/custom.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/demo.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/logback.xml create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/messages.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/messages_fr.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/public/error/404.html create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/templates/index.html create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/templates/international.html create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/templates/other.html create mode 100644 spring-custom-aop/spring-custom-aop/src/main/resources/templates/utils.html create mode 100644 spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/context.xml create mode 100644 spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/dispatcher.xml create mode 100644 spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/web.xml create mode 100644 spring-custom-aop/spring-custom-aop/src/main/webapp/annotationservlet.jsp create mode 100644 spring-custom-aop/spring-custom-aop/src/main/webapp/index.jsp create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithServletComponentIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithoutServletComponentIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/git/CommitIdIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/intro/AppLiveTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/utils/UtilsControllerTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/webjar/WebjarsdemoApplicationIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/ApplicationIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/DemoApplicationIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooComponentTests.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJPATest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJsonTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/FooRepositoryIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/HibernateSessionIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/NoHibernateSessionIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/client/DetailsServiceClientIntegrationTest.java create mode 100644 spring-custom-aop/spring-custom-aop/src/test/resources/application.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/test/resources/exception-hibernate.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/test/resources/exception.properties create mode 100644 spring-custom-aop/spring-custom-aop/src/test/resources/import.sql create mode 100644 spring-custom-aop/spring-custom-aop/src/test/resources/org/baeldung/boot/expected.json diff --git a/groovy-spock/pom.xml b/groovy-spock/pom.xml new file mode 100644 index 0000000000..be84500b0d --- /dev/null +++ b/groovy-spock/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + org.spockframework + groovy-spock + 1.0-SNAPSHOT + jar + Spock Framework - Example Project + + + UTF-8 + UTF-8 + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + 1.5 + + + + compile + testCompile + + + + + + + + + + org.spockframework + spock-core + 1.0-groovy-2.4 + test + + + org.codehaus.groovy + groovy-all + 2.4.7 + + + \ No newline at end of file diff --git a/groovy-spock/src/test/groovy/FirstSpecification.groovy b/groovy-spock/src/test/groovy/FirstSpecification.groovy new file mode 100644 index 0000000000..ed228899a2 --- /dev/null +++ b/groovy-spock/src/test/groovy/FirstSpecification.groovy @@ -0,0 +1,89 @@ +import spock.lang.Specification + +class FirstSpecification extends Specification { + + def "one plus one should equal two"() { + expect: + 1 + 1 == 2 + } + + def "two plus two should equal four"() { + given: + int left = 2 + int right = 2 + + when: + int result = left + right + + then: + result == 4 + } + + def "Should be able to remove from list"() { + given: + def list = [1, 2, 3, 4] + + when: + list.remove(0) + + then: + list == [2, 3, 4] + } + + def "Should get an index out of bounds when removing a non-existent item"() { + given: + def list = [1, 2, 3, 4] + + when: + list.remove(20) + + then: + thrown(IndexOutOfBoundsException) + list.size() == 4 + } + + def "numbers to the power of two"(int a, int b, int c) { + expect: + Math.pow(a, b) == c + + where: + a | b | c + 1 | 2 | 1 + 2 | 2 | 4 + 3 | 2 | 9 + } + + def "Should return default value for mock"() { + given: + def paymentGateway = Mock(PaymentGateway) + + when: + def result = paymentGateway.makePayment(12.99) + + then: + !result + } + + def "Should return true value for mock"() { + given: + def paymentGateway = Mock(PaymentGateway) + paymentGateway.makePayment(20) >> true + + when: + def result = paymentGateway.makePayment(20) + + then: + result + } + + def "Should verify notify was called"() { + given: + def notifier = Mock(Notifier) + + when: + notifier.notify('foo') + + then: + 1 * notifier.notify('foo') + } +} diff --git a/groovy-spock/src/test/groovy/Notifier.groovy b/groovy-spock/src/test/groovy/Notifier.groovy new file mode 100644 index 0000000000..d92d0f86ef --- /dev/null +++ b/groovy-spock/src/test/groovy/Notifier.groovy @@ -0,0 +1,3 @@ +interface Notifier { + void notify(String message) +} \ No newline at end of file diff --git a/groovy-spock/src/test/groovy/PaymentGateway.groovy b/groovy-spock/src/test/groovy/PaymentGateway.groovy new file mode 100644 index 0000000000..2a66e050f9 --- /dev/null +++ b/groovy-spock/src/test/groovy/PaymentGateway.groovy @@ -0,0 +1,3 @@ +interface PaymentGateway { + boolean makePayment(BigDecimal amount) +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 76f7247f51..c8d060ec04 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ + groovy-spock gson guava guava18 diff --git a/spring-custom-aop/spring-custom-aop/.gitignore b/spring-custom-aop/spring-custom-aop/.gitignore new file mode 100644 index 0000000000..60be5b80aa --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/.gitignore @@ -0,0 +1,4 @@ +/target/ +.settings/ +.classpath +.project diff --git a/spring-custom-aop/spring-custom-aop/README.MD b/spring-custom-aop/spring-custom-aop/README.MD new file mode 100644 index 0000000000..9fe18aaacc --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/README.MD @@ -0,0 +1,13 @@ +###The Course +The "REST With Spring" Classes: http://bit.ly/restwithspring + +###Relevant Articles: +- [Quick Guide to @RestClientTest in Spring Boot](http://www.baeldung.com/restclienttest-in-spring-boot) +- [Intro to Spring Boot Starters](http://www.baeldung.com/spring-boot-starters) +- [A Guide to Spring in Eclipse STS](http://www.baeldung.com/eclipse-sts-spring) +- [Introduction to WebJars](http://www.baeldung.com/maven-webjars) +- [Create a Fat Jar App with Spring Boot](http://www.baeldung.com/deployable-fat-jar-spring-boot) +- [The @ServletComponentScan Annotation in Spring Boot](http://www.baeldung.com/spring-servletcomponentscan) +- [A Custom Data Binder in Spring MVC](http://www.baeldung.com/spring-mvc-custom-data-binder) +- [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot) +- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet) diff --git a/spring-custom-aop/spring-custom-aop/pom.xml b/spring-custom-aop/spring-custom-aop/pom.xml new file mode 100644 index 0000000000..bab6f1f101 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/pom.xml @@ -0,0 +1,224 @@ + + 4.0.0 + com.baeldung + spring-boot + 0.0.1-SNAPSHOT + war + spring-boot + This is simple boot application for Spring boot actuator test + + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + + org.apache.tomcat.embed + tomcat-embed-jasper + ${tomcat.version} + + + + io.dropwizard.metrics + metrics-core + + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter + + + com.jayway.jsonpath + json-path + test + + + org.springframework.boot + spring-boot-starter-mail + + + org.subethamail + subethasmtp + ${subethasmtp.version} + test + + + + org.webjars + bootstrap + ${bootstrap.version} + + + org.webjars + jquery + ${jquery.version} + + + + com.google.guava + guava + 18.0 + + + + org.apache.tomcat + tomcat-servlet-api + ${tomee-servlet-api.version} + provided + + + + + + spring-boot + + + src/main/resources + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-war-plugin + + + + pl.project13.maven + git-commit-id-plugin + ${git-commit-id-plugin.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + + + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*LiveTest.java + + + **/*IntegrationTest.java + + + + + + + json + + + + + + + + + + + + org.baeldung.boot.DemoApplication + UTF-8 + 1.8 + 4.3.4.RELEASE + 2.2.1 + 3.1.1 + 3.3.7-1 + 3.1.7 + 8.5.11 + + + diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootAnnotatedApp.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootAnnotatedApp.java new file mode 100644 index 0000000000..b4d416dd96 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootAnnotatedApp.java @@ -0,0 +1,25 @@ +package com.baeldung.annotation.servletcomponentscan; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; + +/** + * using the following annotations are equivalent: + *
  • + * @ServletComponentScan + *
  • + * @ServletComponentScan(basePackages = "com.baeldung.annotation.servletcomponentscan.components") + *
  • + * @ServletComponentScan(basePackageClasses = {AttrListener.class, HelloFilter.class, HelloServlet.class, EchoServlet.class}) + *
+ */ +@SpringBootApplication +@ServletComponentScan("com.baeldung.annotation.servletcomponentscan.components") +public class SpringBootAnnotatedApp { + + public static void main(String[] args) { + SpringApplication.run(SpringBootAnnotatedApp.class, args); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootPlainApp.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootPlainApp.java new file mode 100644 index 0000000000..8a39078aac --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/SpringBootPlainApp.java @@ -0,0 +1,13 @@ +package com.baeldung.annotation.servletcomponentscan; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = "com.baeldung.annotation.servletcomponentscan.components") +public class SpringBootPlainApp { + + public static void main(String[] args) { + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/AttrListener.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/AttrListener.java new file mode 100644 index 0000000000..bad39c52c4 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/AttrListener.java @@ -0,0 +1,23 @@ +package com.baeldung.annotation.servletcomponentscan.components; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class AttrListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + servletContextEvent + .getServletContext() + .setAttribute("servlet-context-attr", "test"); + System.out.println("context init"); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + System.out.println("context destroy"); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/EchoServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/EchoServlet.java new file mode 100644 index 0000000000..3419cd0eaf --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/EchoServlet.java @@ -0,0 +1,29 @@ +package com.baeldung.annotation.servletcomponentscan.components; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +@WebServlet(name = "echo servlet", urlPatterns = "/echo") +public class EchoServlet extends HttpServlet { + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) { + try { + Path path = File + .createTempFile("echo", "tmp") + .toPath(); + Files.copy(request.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING); + Files.copy(path, response.getOutputStream()); + Files.delete(path); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloFilter.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloFilter.java new file mode 100644 index 0000000000..dc2368c5b2 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloFilter.java @@ -0,0 +1,32 @@ +package com.baeldung.annotation.servletcomponentscan.components; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.annotation.WebInitParam; +import java.io.IOException; + +@WebFilter(urlPatterns = "/hello", description = "a filter for hello servlet", initParams = { @WebInitParam(name = "msg", value = "filtering ") }, filterName = "hello filter", servletNames = { "echo servlet" }) +public class HelloFilter implements Filter { + + private FilterConfig filterConfig; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + System.out.println("filter init"); + this.filterConfig = filterConfig; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + servletResponse + .getOutputStream() + .print(filterConfig.getInitParameter("msg")); + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + System.out.println("filter destroy"); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloServlet.java new file mode 100644 index 0000000000..aeae7aecc9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/annotation/servletcomponentscan/components/HelloServlet.java @@ -0,0 +1,32 @@ +package com.baeldung.annotation.servletcomponentscan.components; + +import javax.servlet.ServletConfig; +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@WebServlet(urlPatterns = "/hello", initParams = { @WebInitParam(name = "msg", value = "hello")}) +public class HelloServlet extends HttpServlet { + + private ServletConfig servletConfig; + + @Override + public void init(ServletConfig servletConfig){ + this.servletConfig = servletConfig; + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) { + try { + response + .getOutputStream() + .write(servletConfig.getInitParameter("msg").getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitIdApplication.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitIdApplication.java new file mode 100644 index 0000000000..cd696eae70 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitIdApplication.java @@ -0,0 +1,23 @@ +package com.baeldung.git; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.io.ClassPathResource; + +@SpringBootApplication(scanBasePackages = { "com.baeldung.git" }) +public class CommitIdApplication { + public static void main(String[] args) { + SpringApplication.run(CommitIdApplication.class, args); + } + + @Bean + public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { + PropertySourcesPlaceholderConfigurer c = new PropertySourcesPlaceholderConfigurer(); + c.setLocation(new ClassPathResource("git.properties")); + c.setIgnoreResourceNotFound(true); + c.setIgnoreUnresolvablePlaceholders(true); + return c; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitInfoController.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitInfoController.java new file mode 100644 index 0000000000..6d44e02ec2 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/CommitInfoController.java @@ -0,0 +1,30 @@ +package com.baeldung.git; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +public class CommitInfoController { + + @Value("${git.commit.message.short}") + private String commitMessage; + + @Value("${git.branch}") + private String branch; + + @Value("${git.commit.id}") + private String commitId; + + @RequestMapping("/commitId") + public Map getCommitId() { + Map result = new HashMap<>(); + result.put("Commit message", commitMessage); + result.put("Commit branch", branch); + result.put("Commit id", commitId); + return result; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/README.md b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/README.md new file mode 100644 index 0000000000..7e6a597c28 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/git/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Injecting Git Information Into Spring](http://www.baeldung.com/spring-git-information) diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/InternationalizationApp.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/InternationalizationApp.java new file mode 100644 index 0000000000..c92d1c32e6 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/InternationalizationApp.java @@ -0,0 +1,15 @@ +package com.baeldung.internationalization; + +import javax.annotation.security.RolesAllowed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class InternationalizationApp { + @RolesAllowed("*") + public static void main(String[] args) { + System.setProperty("security.basic.enabled", "false"); + SpringApplication.run(InternationalizationApp.class, args); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/MvcConfig.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/MvcConfig.java new file mode 100644 index 0000000000..59f7fd3ba5 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/MvcConfig.java @@ -0,0 +1,38 @@ +package com.baeldung.internationalization.config; + +import java.util.Locale; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "com.baeldung.internationalization.config") +public class MvcConfig extends WebMvcConfigurerAdapter { + + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver slr = new SessionLocaleResolver(); + slr.setDefaultLocale(Locale.US); + return slr; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + lci.setParamName("lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/PageController.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/PageController.java new file mode 100644 index 0000000000..96a534b853 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/internationalization/config/PageController.java @@ -0,0 +1,14 @@ +package com.baeldung.internationalization.config; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class PageController { + + @GetMapping("/international") + public String getInternationalPage() { + return "international"; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/App.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/App.java new file mode 100644 index 0000000000..3db5d3256e --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/App.java @@ -0,0 +1,13 @@ +package com.baeldung.intro; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class App +{ + public static void main( String[] args ) + { + SpringApplication.run(App.class, args); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/controller/HomeController.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/controller/HomeController.java new file mode 100644 index 0000000000..2a7111135c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/intro/controller/HomeController.java @@ -0,0 +1,18 @@ +package com.baeldung.intro.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HomeController { + + @RequestMapping("/") + public String root(){ + return "Index Page"; + } + + @RequestMapping("/local") + public String local(){ + return "/local"; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/ApplicationMain.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/ApplicationMain.java new file mode 100644 index 0000000000..a6ea3757fe --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/ApplicationMain.java @@ -0,0 +1,19 @@ +package com.baeldung.servlets; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; + +@SpringBootApplication +public class ApplicationMain extends SpringBootServletInitializer { + + public static void main(String[] args) { + SpringApplication.run(ApplicationMain.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(ApplicationMain.class); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java new file mode 100644 index 0000000000..eadd40355a --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebAppInitializer.java @@ -0,0 +1,32 @@ +package com.baeldung.servlets.configuration; + +import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +public class WebAppInitializer implements WebApplicationInitializer { + + public void onStartup(ServletContext container) throws ServletException { + + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.register(WebMvcConfigure.class); + ctx.setServletContext(container); + + ServletRegistration.Dynamic servletOne = container.addServlet("SpringProgrammaticDispatcherServlet", new DispatcherServlet(ctx)); + servletOne.setLoadOnStartup(1); + servletOne.addMapping("/"); + + XmlWebApplicationContext xctx = new XmlWebApplicationContext(); + xctx.setConfigLocation("/WEB-INF/context.xml"); + xctx.setServletContext(container); + + ServletRegistration.Dynamic servletTwo = container.addServlet("SpringProgrammaticXMLDispatcherServlet", new DispatcherServlet(xctx)); + servletTwo.setLoadOnStartup(1); + servletTwo.addMapping("/"); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java new file mode 100644 index 0000000000..3d6a10c2ac --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/configuration/WebMvcConfigure.java @@ -0,0 +1,39 @@ +package com.baeldung.servlets.configuration; + +import org.springframework.boot.web.support.ErrorPageFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.resource.PathResourceResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +public class WebMvcConfigure extends WebMvcConfigurerAdapter { + + @Bean + public ViewResolver getViewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/WEB-INF/"); + resolver.setSuffix(".jsp"); + return resolver; + } + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/resources/**").addResourceLocations("/resources/").setCachePeriod(3600).resourceChain(true).addResolver(new PathResourceResolver()); + } + + @Bean + public ErrorPageFilter errorPageFilter() { + return new ErrorPageFilter(); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/Constants.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/Constants.java new file mode 100644 index 0000000000..6345d1f969 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/Constants.java @@ -0,0 +1,20 @@ +package com.baeldung.servlets.props; + +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Properties; + +public final class Constants { + + @Autowired + PropertySourcesLoader psl; + + public static final String breakLine = System.getProperty("line.separator"); + private static final PropertyLoader pl = new PropertyLoader(); + private static final Properties mainProps = pl.getProperties("custom.properties"); + public static final String DISPATCHER_SERVLET_NAME = mainProps.getProperty("dispatcher.servlet.name"); + public static final String DISPATCHER_SERVLET_MAPPING = mainProps.getProperty("dispatcher.servlet.mapping"); + private final String EXAMPLE_SERVLET_NAME = psl.getProperty("example.servlet.name"); + private final String EXAMPLE_SERVLET_MAPPING = psl.getProperty("example.servlet.mapping"); + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertyLoader.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertyLoader.java new file mode 100644 index 0000000000..c29da45929 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertyLoader.java @@ -0,0 +1,27 @@ +package com.baeldung.servlets.props; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class PropertyLoader { + private static final Logger log = LoggerFactory.getLogger(PropertyLoader.class); + + public Properties getProperties(String file) { + Properties prop = new Properties(); + InputStream input = null; + try { + input = getClass().getResourceAsStream(file); + prop.load(input); + if (input != null) { + input.close(); + } + } catch (IOException ex) { + log.error("IOException: " + ex); + } + return prop; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java new file mode 100644 index 0000000000..56a6751326 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/props/PropertySourcesLoader.java @@ -0,0 +1,23 @@ +package com.baeldung.servlets.props; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.ConfigurableEnvironment; + +@Configuration +@ComponentScan(basePackages = { "com.baeldung.*" }) +@PropertySource("classpath:custom.properties") public class PropertySourcesLoader { + + private static final Logger log = LoggerFactory.getLogger(PropertySourcesLoader.class); + + @Autowired + ConfigurableEnvironment env; + + public String getProperty(String key) { + return env.getProperty(key); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java new file mode 100644 index 0000000000..49dd9404b7 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/GenericCustomServlet.java @@ -0,0 +1,18 @@ +package com.baeldung.servlets.servlets; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public class GenericCustomServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println("

Hello World

"); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java new file mode 100644 index 0000000000..b50a7d5454 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/AnnotationServlet.java @@ -0,0 +1,20 @@ +package com.baeldung.servlets.servlets.javaee; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@WebServlet(name = "AnnotationServlet", + description = "Example Servlet Using Annotations", + urlPatterns = { "/annotationservlet" }) +public class AnnotationServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/annotationservlet.jsp").forward(request, response); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java new file mode 100644 index 0000000000..c7b373064f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/javaee/EEWebXmlServlet.java @@ -0,0 +1,20 @@ +package com.baeldung.servlets.servlets.javaee; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +public class EEWebXmlServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println("

Hello World

"); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java new file mode 100644 index 0000000000..e3c225d429 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/SpringRegistrationBeanServlet.java @@ -0,0 +1,17 @@ +package com.baeldung.servlets.servlets.springboot; + +import com.baeldung.servlets.servlets.GenericCustomServlet; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpringRegistrationBeanServlet { + + @Bean + public ServletRegistrationBean genericCustomServlet() { + ServletRegistrationBean bean = new ServletRegistrationBean(new GenericCustomServlet(), "/springregistrationbeanservlet/*"); + bean.setLoadOnStartup(1); + return bean; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java new file mode 100644 index 0000000000..9e460d03a8 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/servlets/servlets/springboot/embedded/EmbeddedTomcatExample.java @@ -0,0 +1,16 @@ +package com.baeldung.servlets.servlets.springboot.embedded; + +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EmbeddedTomcatExample { + + @Bean + public EmbeddedServletContainerFactory servletContainer() { + TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(); + return tomcat; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/Application.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/Application.java new file mode 100644 index 0000000000..a3d9f9130c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/Application.java @@ -0,0 +1,18 @@ +package com.baeldung.utils; + +import javax.annotation.security.RolesAllowed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages="com.baeldung.utils") +public class Application { + + @RolesAllowed("*") + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/controller/UtilsController.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/controller/UtilsController.java new file mode 100644 index 0000000000..7b4827cdf2 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/utils/controller/UtilsController.java @@ -0,0 +1,49 @@ +package com.baeldung.utils.controller; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.bind.ServletRequestUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.util.WebUtils; + +@Controller +public class UtilsController { + + @GetMapping("/utils") + public String webUtils(Model model) { + return "utils"; + } + + @PostMapping("/setParam") + public String post(HttpServletRequest request, Model model) { + String param = ServletRequestUtils.getStringParameter(request, "param", "DEFAULT"); + +// Long param = ServletRequestUtils.getLongParameter(request, "param",1L); +// boolean param = ServletRequestUtils.getBooleanParameter(request, "param", true); +// double param = ServletRequestUtils.getDoubleParameter(request, "param", 1000); +// float param = ServletRequestUtils.getFloatParameter(request, "param", (float) 1.00); +// int param = ServletRequestUtils.getIntParameter(request, "param", 100); + +// try { +// ServletRequestUtils.getRequiredStringParameter(request, "param"); +// } catch (ServletRequestBindingException e) { +// e.printStackTrace(); +// } + + WebUtils.setSessionAttribute(request, "parameter", param); + model.addAttribute("parameter", "You set: "+(String) WebUtils.getSessionAttribute(request, "parameter")); + return "utils"; + } + + @GetMapping("/other") + public String other(HttpServletRequest request, Model model) { + String param = (String) WebUtils.getSessionAttribute(request, "parameter"); + model.addAttribute("parameter", param); + return "other"; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/TestController.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/TestController.java new file mode 100644 index 0000000000..e8e7fd5ce9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/TestController.java @@ -0,0 +1,15 @@ +package com.baeldung.webjar; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class TestController { + + @RequestMapping(value = "/") + public String welcome(Model model) { + return "index"; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java new file mode 100644 index 0000000000..d2135754c9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.webjar; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +public class WebjarsdemoApplication { + + public static void main(String[] args) { + SpringApplication.run(WebjarsdemoApplication.class, args); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/Application.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/Application.java new file mode 100644 index 0000000000..aae0c427a9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/Application.java @@ -0,0 +1,13 @@ +package org.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.context.ApplicationContext; + +@org.springframework.boot.autoconfigure.SpringBootApplication +public class Application { + private static ApplicationContext applicationContext; + + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/DemoApplication.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/DemoApplication.java new file mode 100644 index 0000000000..e61d140396 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/DemoApplication.java @@ -0,0 +1,14 @@ +package org.baeldung.boot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + System.setProperty("spring.config.name", "demo"); + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/components/FooService.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/components/FooService.java new file mode 100644 index 0000000000..235fd43299 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/components/FooService.java @@ -0,0 +1,21 @@ +package org.baeldung.boot.components; + +import org.baeldung.boot.model.Foo; +import org.baeldung.boot.repository.FooRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class FooService { + + @Autowired + private FooRepository fooRepository; + + public Foo getFooWithId(Integer id) throws Exception { + return fooRepository.findOne(id); + } + + public Foo getFooWithName(String name) { + return fooRepository.findByName(name); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/CommonException.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/CommonException.java new file mode 100644 index 0000000000..1f008440e6 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/CommonException.java @@ -0,0 +1,13 @@ +package org.baeldung.boot.exceptions; + +public class CommonException extends RuntimeException{ + + /** + * + */ + private static final long serialVersionUID = 3080004140659213332L; + + public CommonException(String message){ + super(message); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java new file mode 100644 index 0000000000..68ef3fa389 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/exceptions/FooNotFoundException.java @@ -0,0 +1,13 @@ +package org.baeldung.boot.exceptions; + +public class FooNotFoundException extends RuntimeException{ + + /** + * + */ + private static final long serialVersionUID = 9042200028456133589L; + + public FooNotFoundException(String message){ + super(message); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/model/Foo.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/model/Foo.java new file mode 100644 index 0000000000..ac8a8fe429 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/model/Foo.java @@ -0,0 +1,46 @@ +package org.baeldung.boot.model; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Foo implements Serializable { + private static final long serialVersionUID = 1L; + @Id + @GeneratedValue + private Integer id; + private String name; + + public Foo() { + } + + public Foo(String name) { + this.name = name; + } + + + public Foo(Integer id, String name) { + super(); + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/repository/FooRepository.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/repository/FooRepository.java new file mode 100644 index 0000000000..09d6975dba --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/repository/FooRepository.java @@ -0,0 +1,8 @@ +package org.baeldung.boot.repository; + +import org.baeldung.boot.model.Foo; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FooRepository extends JpaRepository { + public Foo findByName(String name); +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/service/FooController.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/service/FooController.java new file mode 100644 index 0000000000..834fa342e2 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/boot/service/FooController.java @@ -0,0 +1,26 @@ +package org.baeldung.boot.service; + +import org.baeldung.boot.components.FooService; +import org.baeldung.boot.model.Foo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class FooController { + + @Autowired + private FooService fooService; + + @GetMapping("/{id}") + public Foo getFooWithId(@PathVariable Integer id) throws Exception { + return fooService.getFooWithId(id); + } + + @GetMapping("/") + public Foo getFooWithName(@RequestParam String name) throws Exception { + return fooService.getFooWithName(name); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/Details.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/Details.java new file mode 100644 index 0000000000..2ae3adc38f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/Details.java @@ -0,0 +1,32 @@ +package org.baeldung.client; + +public class Details { + + private String name; + + private String login; + + public Details() { + } + + public Details(String name, String login) { + this.name = name; + this.login = login; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/DetailsServiceClient.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/DetailsServiceClient.java new file mode 100644 index 0000000000..51fa7c6181 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/client/DetailsServiceClient.java @@ -0,0 +1,20 @@ +package org.baeldung.client; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class DetailsServiceClient { + + private final RestTemplate restTemplate; + + public DetailsServiceClient(RestTemplateBuilder restTemplateBuilder) { + restTemplate = restTemplateBuilder.build(); + } + + public Details getUserDetails(String name) { + return restTemplate.getForObject("/{name}/details", Details.class, name); + } + +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/MyCustomErrorController.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/MyCustomErrorController.java new file mode 100644 index 0000000000..a50b88f94b --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/MyCustomErrorController.java @@ -0,0 +1,24 @@ +package org.baeldung.common.error; + +import org.springframework.boot.autoconfigure.web.ErrorController; +import org.springframework.web.bind.annotation.RequestMapping; + +public class MyCustomErrorController implements ErrorController { + + private static final String PATH = "/error"; + + public MyCustomErrorController() { + // TODO Auto-generated constructor stub + } + + @RequestMapping(value = PATH) + public String error() { + return "Error heaven"; + } + + @Override + public String getErrorPath() { + return PATH; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/SpringHelloServletRegistrationBean.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/SpringHelloServletRegistrationBean.java new file mode 100644 index 0000000000..774cf1b970 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/SpringHelloServletRegistrationBean.java @@ -0,0 +1,15 @@ +package org.baeldung.common.error; + +import org.springframework.boot.web.servlet.ServletRegistrationBean; + +import javax.servlet.Servlet; + +public class SpringHelloServletRegistrationBean extends ServletRegistrationBean { + + public SpringHelloServletRegistrationBean() { + } + + public SpringHelloServletRegistrationBean(Servlet servlet, String... urlMappings) { + super(servlet, urlMappings); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/controller/ErrorController.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/controller/ErrorController.java new file mode 100644 index 0000000000..9e63418a02 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/error/controller/ErrorController.java @@ -0,0 +1,22 @@ +package org.baeldung.common.error.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ErrorController { + + public ErrorController() { + } + + @RequestMapping("/400") + String error400() { + return "Error Code: 400 occured."; + } + + @RequestMapping("/errorHeaven") + String errorHeaven() { + return "You have reached the heaven of errors!!!"; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/properties/MyServletContainerCustomizationBean.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/properties/MyServletContainerCustomizationBean.java new file mode 100644 index 0000000000..3d239f8944 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/properties/MyServletContainerCustomizationBean.java @@ -0,0 +1,25 @@ +package org.baeldung.common.properties; + +import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.boot.web.servlet.ErrorPage; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +@Component +public class MyServletContainerCustomizationBean implements EmbeddedServletContainerCustomizer { + + public MyServletContainerCustomizationBean() { + + } + + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + container.setPort(8084); + container.setContextPath("/springbootapp"); + + container.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400")); + container.addErrorPages(new ErrorPage("/errorHeaven")); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/resources/ExecutorServiceExitCodeGenerator.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/resources/ExecutorServiceExitCodeGenerator.java new file mode 100644 index 0000000000..07f57ec1ef --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/common/resources/ExecutorServiceExitCodeGenerator.java @@ -0,0 +1,29 @@ +package org.baeldung.common.resources; + +import java.util.Objects; +import java.util.concurrent.ExecutorService; + +import org.springframework.boot.ExitCodeGenerator; + +public class ExecutorServiceExitCodeGenerator implements ExitCodeGenerator { + + private ExecutorService executorService; + + public ExecutorServiceExitCodeGenerator(ExecutorService executorService) { + } + + @Override + public int getExitCode() { + int returnCode = 0; + try { + if (!Objects.isNull(executorService)) { + executorService.shutdownNow(); + returnCode = 1; + } + } catch (SecurityException ex) { + returnCode = 0; + } + return returnCode; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/config/WebConfig.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/config/WebConfig.java new file mode 100644 index 0000000000..4ef407823e --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/config/WebConfig.java @@ -0,0 +1,17 @@ +package org.baeldung.config; + +import org.baeldung.web.resolver.HeaderVersionArgumentResolver; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import java.util.List; + +@Configuration +public class WebConfig extends WebMvcConfigurerAdapter { + + @Override + public void addArgumentResolvers(final List argumentResolvers) { + argumentResolvers.add(new HeaderVersionArgumentResolver()); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/GenericEntityController.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/GenericEntityController.java new file mode 100644 index 0000000000..7d1ad7d899 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/GenericEntityController.java @@ -0,0 +1,59 @@ +package org.baeldung.controller; + +import org.baeldung.domain.GenericEntity; +import org.baeldung.domain.Modes; +import org.baeldung.web.resolver.Version; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@RestController +public class GenericEntityController { + private List entityList = new ArrayList<>(); + + { + entityList.add(new GenericEntity(1l, "entity_1")); + entityList.add(new GenericEntity(2l, "entity_2")); + entityList.add(new GenericEntity(3l, "entity_3")); + entityList.add(new GenericEntity(4l, "entity_4")); + } + + @RequestMapping("/entity/all") + public List findAll() { + return entityList; + } + + @RequestMapping(value = "/entity", method = RequestMethod.POST) + public GenericEntity addEntity(GenericEntity entity) { + entityList.add(entity); + return entity; + } + + @RequestMapping("/entity/findby/{id}") + public GenericEntity findById(@PathVariable Long id) { + return entityList.stream().filter(entity -> entity.getId().equals(id)).findFirst().get(); + } + + @GetMapping("/entity/findbydate/{date}") + public GenericEntity findByDate(@PathVariable("date") LocalDateTime date) { + return entityList.stream().findFirst().get(); + } + + @GetMapping("/entity/findbymode/{mode}") + public GenericEntity findByEnum(@PathVariable("mode") Modes mode) { + return entityList.stream().findFirst().get(); + } + + @GetMapping("/entity/findbyversion") + public ResponseEntity findByVersion(@Version String version) { + return version != null ? new ResponseEntity(entityList.stream().findFirst().get(), HttpStatus.OK) : new ResponseEntity(HttpStatus.NOT_FOUND); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/HelloWorldServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/HelloWorldServlet.java new file mode 100644 index 0000000000..fc8fefd77e --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/HelloWorldServlet.java @@ -0,0 +1,43 @@ +package org.baeldung.controller.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Objects; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class HelloWorldServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + public HelloWorldServlet() { + super(); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + PrintWriter out = null; + try { + out = response.getWriter(); + out.println("HelloWorldServlet: GET METHOD"); + out.flush(); + } finally { + if (!Objects.isNull(out)) + out.close(); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + PrintWriter out = null; + try { + out = response.getWriter(); + out.println("HelloWorldServlet: POST METHOD"); + out.flush(); + } finally { + if (!Objects.isNull(out)) + out.close(); + } + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/SpringHelloWorldServlet.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/SpringHelloWorldServlet.java new file mode 100644 index 0000000000..16cff5b1fa --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/controller/servlet/SpringHelloWorldServlet.java @@ -0,0 +1,43 @@ +package org.baeldung.controller.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Objects; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class SpringHelloWorldServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + public SpringHelloWorldServlet() { + super(); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + PrintWriter out = null; + try { + out = response.getWriter(); + out.println("SpringHelloWorldServlet: GET METHOD"); + out.flush(); + } finally { + if (!Objects.isNull(out)) + out.close(); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + PrintWriter out = null; + try { + out = response.getWriter(); + out.println("SpringHelloWorldServlet: POST METHOD"); + out.flush(); + } finally { + if (!Objects.isNull(out)) + out.close(); + } + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToEnumConverterFactory.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToEnumConverterFactory.java new file mode 100644 index 0000000000..17c6fd06de --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToEnumConverterFactory.java @@ -0,0 +1,27 @@ +package org.baeldung.converter; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterFactory; +import org.springframework.stereotype.Component; + +@Component +public class StringToEnumConverterFactory implements ConverterFactory { + + private static class StringToEnumConverter implements Converter { + + private Class enumType; + + public StringToEnumConverter(Class enumType) { + this.enumType = enumType; + } + + public T convert(String source) { + return (T) Enum.valueOf(this.enumType, source.trim()); + } + } + + @Override + public Converter getConverter(final Class targetType) { + return new StringToEnumConverter(targetType); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToLocalDateTimeConverter.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToLocalDateTimeConverter.java new file mode 100644 index 0000000000..cbb9e6ddb4 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/converter/StringToLocalDateTimeConverter.java @@ -0,0 +1,16 @@ +package org.baeldung.converter; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Component +public class StringToLocalDateTimeConverter implements Converter { + + @Override + public LocalDateTime convert(final String source) { + return LocalDateTime.parse(source, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/GenericEntity.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/GenericEntity.java new file mode 100644 index 0000000000..7b1d27cb66 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/GenericEntity.java @@ -0,0 +1,42 @@ +package org.baeldung.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class GenericEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + private String value; + + public GenericEntity() { + } + + public GenericEntity(String value) { + this.value = value; + } + + public GenericEntity(Long id, String value) { + this.id = id; + this.value = value; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/Modes.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/Modes.java new file mode 100644 index 0000000000..473406ef26 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/domain/Modes.java @@ -0,0 +1,6 @@ +package org.baeldung.domain; + +public enum Modes { + + ALPHA, BETA; +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/CustomEndpoint.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/CustomEndpoint.java new file mode 100644 index 0000000000..222a54c6ef --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/CustomEndpoint.java @@ -0,0 +1,35 @@ +package org.baeldung.endpoints; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.stereotype.Component; + +@Component +public class CustomEndpoint implements Endpoint> { + + public CustomEndpoint() { + + } + + public String getId() { + return "customEndpoint"; + } + + public boolean isEnabled() { + return true; + } + + public boolean isSensitive() { + return true; + } + + public List invoke() { + // Your logic to display the output + List messages = new ArrayList(); + messages.add("This is message 1"); + messages.add("This is message 2"); + return messages; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/ListEndpoints.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/ListEndpoints.java new file mode 100644 index 0000000000..0add741a1f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/ListEndpoints.java @@ -0,0 +1,23 @@ +package org.baeldung.endpoints; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.AbstractEndpoint; +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.stereotype.Component; + +@Component +public class ListEndpoints extends AbstractEndpoint> { + private List endpoints; + + @Autowired + public ListEndpoints(List endpoints) { + super("listEndpoints"); + this.endpoints = endpoints; + } + + public List invoke() { + return this.endpoints; + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/MyHealthCheck.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/MyHealthCheck.java new file mode 100644 index 0000000000..4410a02d47 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/endpoints/MyHealthCheck.java @@ -0,0 +1,22 @@ +package org.baeldung.endpoints; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +@Component +public class MyHealthCheck implements HealthIndicator { + + public Health health() { + int errorCode = check(); // perform some specific health check + if (errorCode != 0) { + return Health.down().withDetail("Error Code", errorCode).withDetail("Description", "You custom MyHealthCheck endpoint is down").build(); + } + return Health.up().build(); + } + + public int check() { + // Your logic to check health + return 1; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/main/SpringBootApplication.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/main/SpringBootApplication.java new file mode 100644 index 0000000000..b828a5b841 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/main/SpringBootApplication.java @@ -0,0 +1,68 @@ +package org.baeldung.main; + +import org.baeldung.common.error.SpringHelloServletRegistrationBean; +import org.baeldung.common.resources.ExecutorServiceExitCodeGenerator; +import org.baeldung.controller.servlet.HelloWorldServlet; +import org.baeldung.controller.servlet.SpringHelloWorldServlet; +import org.baeldung.service.LoginService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RestController +@EnableAutoConfiguration +@ComponentScan({ "org.baeldung.common.error", "org.baeldung.common.error.controller", "org.baeldung.common.properties", "org.baeldung.common.resources", "org.baeldung.endpoints", "org.baeldung.service", "org.baeldung.monitor.jmx", "org.baeldung.service" }) +public class SpringBootApplication { + + private static ApplicationContext applicationContext; + + @Autowired + private LoginService service; + + @RequestMapping("/") + String home() { + service.login("admin", "admin".toCharArray()); + return "TADA!!! You are in Spring Boot Actuator test application."; + } + + public static void main(String[] args) { + applicationContext = SpringApplication.run(SpringBootApplication.class, args); + } + + @Bean + public ExecutorService executorService() { + return Executors.newFixedThreadPool(10); + } + + @Bean + public HelloWorldServlet helloWorldServlet() { + return new HelloWorldServlet(); + } + + @Bean + public SpringHelloServletRegistrationBean servletRegistrationBean() { + SpringHelloServletRegistrationBean bean = new SpringHelloServletRegistrationBean(new SpringHelloWorldServlet(), "/springHelloWorld/*"); + bean.setLoadOnStartup(1); + bean.addInitParameter("message", "SpringHelloWorldServlet special message"); + return bean; + } + + @Bean + @Autowired + public ExecutorServiceExitCodeGenerator executorServiceExitCodeGenerator(ExecutorService executorService) { + return new ExecutorServiceExitCodeGenerator(executorService); + } + + public void shutDown(ExecutorServiceExitCodeGenerator executorServiceExitCodeGenerator) { + SpringApplication.exit(applicationContext, executorServiceExitCodeGenerator); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/monitor/jmx/MonitoringConfig.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/monitor/jmx/MonitoringConfig.java new file mode 100644 index 0000000000..febe3336eb --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/monitor/jmx/MonitoringConfig.java @@ -0,0 +1,21 @@ +package org.baeldung.monitor.jmx; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; + +@Configuration +public class MonitoringConfig { + @Autowired + private MetricRegistry registry; + + @Bean + public JmxReporter jmxReporter() { + JmxReporter reporter = JmxReporter.forRegistry(registry).build(); + reporter.start(); + return reporter; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/repository/GenericEntityRepository.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/repository/GenericEntityRepository.java new file mode 100644 index 0000000000..7bb1e6dcdc --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/repository/GenericEntityRepository.java @@ -0,0 +1,7 @@ +package org.baeldung.repository; + +import org.baeldung.domain.GenericEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface GenericEntityRepository extends JpaRepository { +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginService.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginService.java new file mode 100644 index 0000000000..34840fad67 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginService.java @@ -0,0 +1,5 @@ +package org.baeldung.service; + +public interface LoginService { + public boolean login(String userName, char[] password); +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginServiceImpl.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginServiceImpl.java new file mode 100644 index 0000000000..2e5ef89c48 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/service/LoginServiceImpl.java @@ -0,0 +1,29 @@ +package org.baeldung.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.stereotype.Service; + +@Service +public class LoginServiceImpl implements LoginService { + + private CounterService counterService; + + @Autowired + public LoginServiceImpl(CounterService counterService) { + this.counterService = counterService; + } + + public boolean login(String userName, char[] password) { + boolean success; + if (userName.equals("admin") && "secret".toCharArray().equals(password)) { + counterService.increment("counter.login.success"); + success = true; + } else { + counterService.increment("counter.login.failure"); + success = false; + } + return success; + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/Application.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/Application.java new file mode 100644 index 0000000000..23d741b98c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/Application.java @@ -0,0 +1,23 @@ +package org.baeldung.session.exception; + +import org.baeldung.boot.model.Foo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean; + +@EntityScan(basePackageClasses = Foo.class) +@SpringBootApplication +public class Application { + public static void main(String[] args) { + System.setProperty("spring.config.name", "exception"); + System.setProperty("spring.profiles.active", "exception"); + SpringApplication.run(Application.class, args); + } + + @Bean + public HibernateJpaSessionFactoryBean sessionFactory() { + return new HibernateJpaSessionFactoryBean(); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepository.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepository.java new file mode 100644 index 0000000000..679d691b26 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepository.java @@ -0,0 +1,10 @@ +package org.baeldung.session.exception.repository; + +import org.baeldung.boot.model.Foo; + +public interface FooRepository { + + void save(Foo foo); + + Foo get(Integer id); +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepositoryImpl.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepositoryImpl.java new file mode 100644 index 0000000000..83de888e5e --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/session/exception/repository/FooRepositoryImpl.java @@ -0,0 +1,25 @@ +package org.baeldung.session.exception.repository; + +import org.baeldung.boot.model.Foo; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +@Profile("exception") +@Repository +public class FooRepositoryImpl implements FooRepository { + @Autowired + private SessionFactory sessionFactory; + + @Override + public void save(Foo foo) { + sessionFactory.getCurrentSession().saveOrUpdate(foo); + } + + @Override + public Foo get(Integer id) { + return sessionFactory.getCurrentSession().get(Foo.class, id); + } + +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/HeaderVersionArgumentResolver.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/HeaderVersionArgumentResolver.java new file mode 100644 index 0000000000..89a77f38d1 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/HeaderVersionArgumentResolver.java @@ -0,0 +1,26 @@ +package org.baeldung.web.resolver; + +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; + +@Component +public class HeaderVersionArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(final MethodParameter methodParameter) { + return methodParameter.getParameterAnnotation(Version.class) != null; + } + + @Override + public Object resolveArgument(final MethodParameter methodParameter, final ModelAndViewContainer modelAndViewContainer, final NativeWebRequest nativeWebRequest, final WebDataBinderFactory webDataBinderFactory) throws Exception { + HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest(); + + return request.getHeader("Version"); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/Version.java b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/Version.java new file mode 100644 index 0000000000..2a9e6e60b3 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/java/org/baeldung/web/resolver/Version.java @@ -0,0 +1,11 @@ +package org.baeldung.web.resolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface Version { +} diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/application.properties b/spring-custom-aop/spring-custom-aop/src/main/resources/application.properties new file mode 100644 index 0000000000..72ed8795c9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/application.properties @@ -0,0 +1,43 @@ +server.port=8080 +server.contextPath=/springbootapp +management.port=8081 +management.address=127.0.0.1 + +endpoints.shutdown.enabled=true + +endpoints.jmx.domain=Spring Sample Application +endpoints.jmx.uniqueNames=true + +##jolokia.config.debug=true +##endpoints.jolokia.enabled=true +##endpoints.jolokia.path=jolokia + +spring.jmx.enabled=true +endpoints.jmx.enabled=true + +## for pretty printing of json when endpoints accessed over HTTP +http.mappers.jsonPrettyPrint=true + +## Configuring info endpoint +info.app.name=Spring Sample Application +info.app.description=This is my first spring boot application G1 +info.app.version=1.0.0 + +## Spring Security Configurations +security.user.name=admin1 +security.user.password=secret1 +management.security.role=SUPERUSER + +logging.level.org.springframework=INFO + +#Servlet Configuration +servlet.name=dispatcherExample +servlet.mapping=/dispatcherExampleURL + +#banner.charset=UTF-8 +#banner.location=classpath:banner.txt +#banner.image.location=classpath:banner.gif +#banner.image.width= //TODO +#banner.image.height= //TODO +#banner.image.margin= //TODO +#banner.image.invert= //TODO \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/banner.txt b/spring-custom-aop/spring-custom-aop/src/main/resources/banner.txt new file mode 100644 index 0000000000..abfa666eb6 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/banner.txt @@ -0,0 +1,14 @@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@########@@@@@@@@@@@@@@@@@@@@@@@@...@@@@@@@@@:..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@#. @@@@@* *@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@#o @@@@@* @@@@@* @@@:*.*@@@@@@@: *8@@@ @@@@&:.#@. @o**@@@@**:@o*o@@:.:@@@@@:.o#@&*:@@@@ +@@@@@@@@@@@@* @@@@@* 8888 8@ @@@8 #@o 8@# .@ @@* :. @* @@@@ @. : &@ ** .@@@@ +@@@@@@@@@@. @ o@@@@@* *@@@o::& .* 8@@@@. @@ 8@@@@. @* @@@@ @. @@@& * @@@@# .@@@@ +@@@@@@@@@& @ @@@@@@* @@@@@@ 8 @@@@ .. o&&&&&&& @@ #@@@@. @* @@@@ @. @@@# * @@@@@ .@@@@ +@@@@@@@@@ @@o @@@@@@@* oooo* 8 @@@& @* @@@ # 88. 88. *& o#: @. @@@# *@ &#& .@@@@ +@@@@@@@@# @@@8 @@@@@@@* .*@@@#. *@@ @@@& :#@@@o .@@: *&@8 @o o@@: @. @@@# *@@#. :8# .@@@@ +@@@@@@@@@ @@@@ &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# o@@@@ @@@@@ +@@@@@& &@@@@ 8@@@@@@@@@8&8@@@@@#8#@@@o8@#&@@o&@@@&@@8@@&@@@@88@@8#@8&@@##@@@@@@#8@@#8@@88@@@@@ *@@@@@@@ +@@@# #@@@@#. @@@@@@@@@@@@@8@@8#o@&#@@@@o.@o*@@*.@@@.@&:8o8*@@@8&@@#@@@8@@@@8@#@@@8&@@@@@@#@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/custom.properties b/spring-custom-aop/spring-custom-aop/src/main/resources/custom.properties new file mode 100644 index 0000000000..34f31bcd50 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/custom.properties @@ -0,0 +1,4 @@ +dispatcher.servlet.name=dispatcherExample +dispatcher.servlet.mapping=/dispatcherExampleURL +example.servlet.name=dispatcherExample +example.servlet.mapping=/dispatcherExampleURL \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/demo.properties b/spring-custom-aop/spring-custom-aop/src/main/resources/demo.properties new file mode 100644 index 0000000000..649b64f59b --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/demo.properties @@ -0,0 +1,6 @@ +spring.output.ansi.enabled=never +server.port=7070 + +# Security +security.user.name=admin +security.user.password=password \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/logback.xml b/spring-custom-aop/spring-custom-aop/src/main/resources/logback.xml new file mode 100644 index 0000000000..78913ee76f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/messages.properties b/spring-custom-aop/spring-custom-aop/src/main/resources/messages.properties new file mode 100644 index 0000000000..e4dbc44c3f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/messages.properties @@ -0,0 +1,4 @@ +greeting=Hello! Welcome to our website! +lang.change=Change the language +lang.eng=English +lang.fr=French \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/messages_fr.properties b/spring-custom-aop/spring-custom-aop/src/main/resources/messages_fr.properties new file mode 100644 index 0000000000..ac5853717d --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/messages_fr.properties @@ -0,0 +1,4 @@ +greeting=Bonjour! Bienvenue sur notre site! +lang.change=Changez la langue +lang.eng=Anglais +lang.fr=Francais \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/public/error/404.html b/spring-custom-aop/spring-custom-aop/src/main/resources/public/error/404.html new file mode 100644 index 0000000000..df83ce219b --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/public/error/404.html @@ -0,0 +1,8 @@ + + + RESOURCE NOT FOUND + + +

404 RESOURCE NOT FOUND

+ + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/templates/index.html b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/index.html new file mode 100644 index 0000000000..2c4387ed10 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/index.html @@ -0,0 +1,19 @@ + + + WebJars Demo + + + + +

+
+ × + Success! It is working as we expected. +
+
+ + + + + + diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/templates/international.html b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/international.html new file mode 100644 index 0000000000..a2a5fbb591 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/international.html @@ -0,0 +1,29 @@ + + + + +Home + + + + +

+ +

+: + + + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/templates/other.html b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/other.html new file mode 100644 index 0000000000..d13373f9fe --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/other.html @@ -0,0 +1,16 @@ + + + + +Spring Utils Demo + + + + Parameter set by you:

+ + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/resources/templates/utils.html b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/utils.html new file mode 100644 index 0000000000..93030f424f --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/resources/templates/utils.html @@ -0,0 +1,23 @@ + + + + +Spring Utils Demo + + + +

+

Set Parameter:

+

+ + +

+
+Another Page + + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/context.xml b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/context.xml new file mode 100644 index 0000000000..263bed4430 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/context.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/dispatcher.xml b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/dispatcher.xml new file mode 100644 index 0000000000..ade8e66777 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/dispatcher.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/web.xml b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..60a4b079de --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,40 @@ + + + JSP + + index.html + index.htm + index.jsp + + + + + EEWebXmlServlet + com.baeldung.servlets.javaee.EEWebXmlServlet + + + + EEWebXmlServlet + /eewebxmlservlet + + + + + SpringBootWebXmlServlet + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + /WEB-INF/dispatcher.xml + + 1 + + + + SpringBootWebXmlServlet + / + + + + diff --git a/spring-custom-aop/spring-custom-aop/src/main/webapp/annotationservlet.jsp b/spring-custom-aop/spring-custom-aop/src/main/webapp/annotationservlet.jsp new file mode 100644 index 0000000000..f21748df50 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/webapp/annotationservlet.jsp @@ -0,0 +1 @@ +

Annotation Servlet!

\ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/main/webapp/index.jsp b/spring-custom-aop/spring-custom-aop/src/main/webapp/index.jsp new file mode 100644 index 0000000000..e534282777 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/main/webapp/index.jsp @@ -0,0 +1 @@ +

Hello!

\ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithServletComponentIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithServletComponentIntegrationTest.java new file mode 100644 index 0000000000..8d5eb56bf4 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithServletComponentIntegrationTest.java @@ -0,0 +1,65 @@ +package com.baeldung.annotation.servletcomponentscan; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringBootAnnotatedApp.class) +@AutoConfigureMockMvc +@TestPropertySource(properties = { "security.basic.enabled=false" }) +public class SpringBootWithServletComponentIntegrationTest { + + @Autowired private ServletContext servletContext; + + @Test + public void givenServletContext_whenAccessAttrs_thenFoundAttrsPutInServletListner() { + assertNotNull(servletContext); + assertNotNull(servletContext.getAttribute("servlet-context-attr")); + assertEquals("test", servletContext.getAttribute("servlet-context-attr")); + } + + @Test + public void givenServletContext_whenCheckHelloFilterMappings_thenCorrect() { + assertNotNull(servletContext); + FilterRegistration filterRegistration = servletContext.getFilterRegistration("hello filter"); + + assertNotNull(filterRegistration); + assertTrue(filterRegistration + .getServletNameMappings() + .contains("echo servlet")); + } + + @Autowired private TestRestTemplate restTemplate; + + @Test + public void givenServletFilter_whenGetHello_thenRequestFiltered() { + ResponseEntity responseEntity = this.restTemplate.getForEntity("/hello", String.class); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals("filtering hello", responseEntity.getBody()); + } + + @Test + public void givenFilterAndServlet_whenPostEcho_thenEchoFiltered() { + ResponseEntity responseEntity = this.restTemplate.postForEntity("/echo", "echo", String.class); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals("filtering echo", responseEntity.getBody()); + } + + + +} + + diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithoutServletComponentIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithoutServletComponentIntegrationTest.java new file mode 100644 index 0000000000..64507ad02c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/annotation/servletcomponentscan/SpringBootWithoutServletComponentIntegrationTest.java @@ -0,0 +1,50 @@ +package com.baeldung.annotation.servletcomponentscan; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; + +import static org.junit.Assert.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringBootPlainApp.class) +@AutoConfigureMockMvc +@TestPropertySource(properties = { "security.basic.enabled=false" }) +public class SpringBootWithoutServletComponentIntegrationTest { + + @Autowired private ServletContext servletContext; + + @Autowired private TestRestTemplate restTemplate; + + @Test + public void givenServletContext_whenAccessAttrs_thenNotFound() { + assertNull(servletContext.getAttribute("servlet-context-attr")); + } + + @Test + public void givenServletFilter_whenGetHello_thenEndpointNotFound() { + ResponseEntity responseEntity = this.restTemplate.getForEntity("/hello", String.class); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void givenServletContext_whenCheckFilterMappings_thenEmpty() { + assertNotNull(servletContext); + FilterRegistration filterRegistration = servletContext.getFilterRegistration("hello filter"); + + assertNull(filterRegistration); + } + +} + + diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/git/CommitIdIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/git/CommitIdIntegrationTest.java new file mode 100644 index 0000000000..348d594c05 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/git/CommitIdIntegrationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.git; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = CommitIdApplication.class) +public class CommitIdIntegrationTest { + + private static final Logger LOG = LoggerFactory.getLogger(CommitIdIntegrationTest.class); + + @Value("${git.commit.message.short:UNKNOWN}") + private String commitMessage; + + @Value("${git.branch:UNKNOWN}") + private String branch; + + @Value("${git.commit.id:UNKNOWN}") + private String commitId; + + @Test + public void whenInjecting_shouldDisplay() throws Exception { + + LOG.info(commitId); + LOG.info(commitMessage); + LOG.info(branch); + + assertThat(commitMessage).isNotEqualTo("UNKNOWN"); + + assertThat(branch).isNotEqualTo("UNKNOWN"); + + assertThat(commitId).isNotEqualTo("UNKNOWN"); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/intro/AppLiveTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/intro/AppLiveTest.java new file mode 100644 index 0000000000..af46fe0423 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/intro/AppLiveTest.java @@ -0,0 +1,41 @@ +package com.baeldung.intro; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.hamcrest.Matchers.equalTo; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +@TestPropertySource(properties = { "security.basic.enabled=false" }) +public class AppLiveTest { + + @Autowired + private MockMvc mvc; + + @Test + public void getIndex() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo("Index Page"))); + } + + @Test + public void getLocal() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/local").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo("/local"))); + } + +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/utils/UtilsControllerTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/utils/UtilsControllerTest.java new file mode 100644 index 0000000000..7aed45dbb0 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/utils/UtilsControllerTest.java @@ -0,0 +1,41 @@ +package com.baeldung.utils; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +import com.baeldung.utils.controller.UtilsController; + +public class UtilsControllerTest { + + @InjectMocks + private UtilsController utilsController; + + private MockMvc mockMvc; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + this.mockMvc = MockMvcBuilders.standaloneSetup(utilsController) + .build(); + + } + + @Test + public void givenParameter_setRequestParam_andSetSessionAttribute() throws Exception { + String param = "testparam"; + this.mockMvc.perform( + post("/setParam") + .param("param", param) + .sessionAttr("parameter", param)) + .andExpect(status().isOk()); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/webjar/WebjarsdemoApplicationIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/webjar/WebjarsdemoApplicationIntegrationTest.java new file mode 100644 index 0000000000..d6e71dcf6b --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/com/baeldung/webjar/WebjarsdemoApplicationIntegrationTest.java @@ -0,0 +1,18 @@ +package com.baeldung.webjar; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = WebjarsdemoApplication.class) +@WebAppConfiguration +public class WebjarsdemoApplicationIntegrationTest { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java new file mode 100644 index 0000000000..87c59a4662 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java @@ -0,0 +1,66 @@ +package org.baeldung; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + +import org.baeldung.domain.Modes; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.nio.charset.Charset; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = Application.class) +@WebAppConfiguration +public class SpringBootApplicationIntegrationTest { + @Autowired + private WebApplicationContext webApplicationContext; + private MockMvc mockMvc; + + @Before + public void setupMockMvc() { + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + public void givenRequestHasBeenMade_whenMeetsAllOfGivenConditions_thenCorrect() throws Exception { + MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + mockMvc.perform(MockMvcRequestBuilders.get("/entity/all")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(contentType)).andExpect(jsonPath("$", hasSize(4))); + } + + @Test + public void givenRequestHasBeenMade_whenMeetsFindByDateOfGivenConditions_thenCorrect() throws Exception { + MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + mockMvc.perform(MockMvcRequestBuilders.get("/entity/findbydate/{date}", "2011-12-03T10:15:30")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(contentType)) + .andExpect(jsonPath("$.id", equalTo(1))); + } + + @Test + public void givenRequestHasBeenMade_whenMeetsFindByModeOfGivenConditions_thenCorrect() throws Exception { + MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + mockMvc.perform(MockMvcRequestBuilders.get("/entity/findbymode/{mode}", Modes.ALPHA.name())).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(contentType)).andExpect(jsonPath("$.id", equalTo(1))); + } + + @Test + public void givenRequestHasBeenMade_whenMeetsFindByVersionOfGivenConditions_thenCorrect() throws Exception { + MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); + + mockMvc.perform(MockMvcRequestBuilders.get("/entity/findbyversion").header("Version", "1.0.0")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(contentType)) + .andExpect(jsonPath("$.id", equalTo(1))); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java new file mode 100644 index 0000000000..d4b19e6a1d --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java @@ -0,0 +1,27 @@ +package org.baeldung; + +import org.baeldung.domain.GenericEntity; +import org.baeldung.repository.GenericEntityRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = Application.class) +public class SpringBootJPAIntegrationTest { + @Autowired + private GenericEntityRepository genericEntityRepository; + + @Test + public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() { + GenericEntity genericEntity = genericEntityRepository.save(new GenericEntity("test")); + GenericEntity foundedEntity = genericEntityRepository.findOne(genericEntity.getId()); + assertNotNull(foundedEntity); + assertEquals(genericEntity.getValue(), foundedEntity.getValue()); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java new file mode 100644 index 0000000000..10e3d6d60b --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java @@ -0,0 +1,81 @@ +package org.baeldung; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.context.WebApplicationContext; +import org.subethamail.wiser.Wiser; +import org.subethamail.wiser.WiserMessage; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.List; + +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = Application.class) +public class SpringBootMailIntegrationTest { + @Autowired + private JavaMailSender javaMailSender; + + private Wiser wiser; + + private String userTo = "user2@localhost"; + private String userFrom = "user1@localhost"; + private String subject = "Test subject"; + private String textMail = "Text subject mail"; + + @Before + public void setUp() throws Exception { + final int TEST_PORT = 8025; + wiser = new Wiser(TEST_PORT); + wiser.start(); + } + + @After + public void tearDown() throws Exception { + wiser.stop(); + } + + @Test + public void givenMail_whenSendAndReceived_thenCorrect() throws Exception { + SimpleMailMessage message = composeEmailMessage(); + javaMailSender.send(message); + List messages = wiser.getMessages(); + + assertThat(messages, hasSize(1)); + WiserMessage wiserMessage = messages.get(0); + assertEquals(userFrom, wiserMessage.getEnvelopeSender()); + assertEquals(userTo, wiserMessage.getEnvelopeReceiver()); + assertEquals(subject, getSubject(wiserMessage)); + assertEquals(textMail, getMessage(wiserMessage)); + } + + private String getMessage(WiserMessage wiserMessage) throws MessagingException, IOException { + return wiserMessage.getMimeMessage().getContent().toString().trim(); + } + + private String getSubject(WiserMessage wiserMessage) throws MessagingException { + return wiserMessage.getMimeMessage().getSubject(); + } + + private SimpleMailMessage composeEmailMessage() { + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setTo(userTo); + mailMessage.setReplyTo(userFrom); + mailMessage.setFrom(userFrom); + mailMessage.setSubject(subject); + mailMessage.setText(textMail); + return mailMessage; + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/ApplicationIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/ApplicationIntegrationTest.java new file mode 100644 index 0000000000..57a8abc1ee --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/ApplicationIntegrationTest.java @@ -0,0 +1,17 @@ +package org.baeldung.boot; + +import org.baeldung.session.exception.Application; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = Application.class) +@TestPropertySource("classpath:exception.properties") +public class ApplicationIntegrationTest { + @Test + public void contextLoads() { + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/DemoApplicationIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/DemoApplicationIntegrationTest.java new file mode 100644 index 0000000000..4fcea35b4a --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/DemoApplicationIntegrationTest.java @@ -0,0 +1,17 @@ +package org.baeldung.boot; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = DemoApplication.class) +@WebAppConfiguration +public class DemoApplicationIntegrationTest { + + @Test + public void contextLoads() { + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooComponentTests.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooComponentTests.java new file mode 100644 index 0000000000..72ccc0bfb8 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooComponentTests.java @@ -0,0 +1,70 @@ +package org.baeldung.boot; + +import org.baeldung.boot.components.FooService; +import org.baeldung.boot.model.Foo; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = DemoApplication.class, + webEnvironment = WebEnvironment.RANDOM_PORT) +public class FooComponentTests { + + @Autowired + private TestRestTemplate testRestTemplate; + + @SpyBean + private FooService fooService; + + @Before + public void init() throws Exception { + Foo foo = new Foo(); + foo.setId(5); + foo.setName("MOCKED_FOO"); + + doReturn(foo).when(fooService).getFooWithId(anyInt()); + + // doCallRealMethod().when(fooComponent).getFooWithName(anyString()); + } + + @Test + public void givenInquiryingFooWithId_whenFooComponentIsMocked_thenAssertMockedResult() { + Map pathVariables = new HashMap<>(); + pathVariables.put("id", "1"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); + + assertNotNull(fooResponse); + assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); + assertEquals(5, fooResponse.getBody().getId().longValue()); + assertEquals("MOCKED_FOO", fooResponse.getBody().getName()); + } + + @Test + public void givenInquiryingFooWithName_whenFooComponentIsMocked_thenAssertMockedResult() { + Map pathVariables = new HashMap<>(); + pathVariables.put("name", "Foo_Name"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); + + assertNotNull(fooResponse); + assertEquals(HttpStatus.OK, fooResponse.getStatusCode()); + assertEquals(1, fooResponse.getBody().getId().longValue()); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooIntegrationTest.java new file mode 100644 index 0000000000..932cce26d5 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooIntegrationTest.java @@ -0,0 +1,43 @@ +package org.baeldung.boot; +import java.util.HashMap; +import java.util.Map; + +import org.baeldung.boot.DemoApplication; +import org.baeldung.boot.model.Foo; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=DemoApplication.class,webEnvironment = WebEnvironment.RANDOM_PORT) +public class FooIntegrationTest { + + @Autowired + private TestRestTemplate testRestTemplate; + + + @Test + public void givenInquiryingFooWithId_whenIdIsValid_thenHttpStatusOK(){ + Map pathVariables = new HashMap(); + pathVariables.put("id", "1"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/{id}", Foo.class, pathVariables); + Assert.assertNotNull(fooResponse); + Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); + } + + @Test + public void givenInquiryingFooWithName_whenNameIsValid_thenHttpStatusOK(){ + Map pathVariables = new HashMap(); + pathVariables.put("name", "Foo_Name"); + ResponseEntity fooResponse = testRestTemplate.getForEntity("/?name={name}", Foo.class, pathVariables); + Assert.assertNotNull(fooResponse); + Assert.assertEquals(HttpStatus.OK,fooResponse.getStatusCode()); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJPATest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJPATest.java new file mode 100644 index 0000000000..c29aa64e6c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJPATest.java @@ -0,0 +1,34 @@ +package org.baeldung.boot; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.baeldung.boot.model.Foo; +import org.baeldung.boot.repository.FooRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@DataJpaTest +public class FooJPATest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private FooRepository repository; + + @Test + public void findFooByName() { + this.entityManager.persist(new Foo("Foo_Name_2")); + Foo foo = this.repository.findByName("Foo_Name_2"); + assertNotNull(foo); + assertEquals("Foo_Name_2",foo.getName()); + // Due to having Insert query for Foo with Id 1, so TestEntityManager generates new Id of 2 + assertEquals(2l,foo.getId().longValue()); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJsonTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJsonTest.java new file mode 100644 index 0000000000..2789ed0a8c --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/FooJsonTest.java @@ -0,0 +1,35 @@ +package org.baeldung.boot; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.baeldung.boot.model.Foo; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@JsonTest +public class FooJsonTest { + + @Autowired + private JacksonTester json; + + + @Test + public void testSerialize() throws Exception { + Foo foo = new Foo(3, "Foo_Name_3"); + assertThat(this.json.write(foo)).isEqualToJson("expected.json"); + assertThat(this.json.write(foo)).hasJsonPathStringValue("@.name"); + assertThat(this.json.write(foo)).extractingJsonPathStringValue("@.name").isEqualTo("Foo_Name_3"); + } + + @Test + public void testDeserialize() throws Exception { + String content = "{\"id\":4,\"name\":\"Foo_Name_4\"}"; + assertThat(this.json.parseObject(content).getName()).isEqualTo("Foo_Name_4"); + assertThat(this.json.parseObject(content).getId()==4); + } +} \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/FooRepositoryIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/FooRepositoryIntegrationTest.java new file mode 100644 index 0000000000..a844b26b2d --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/FooRepositoryIntegrationTest.java @@ -0,0 +1,34 @@ +package org.baeldung.boot.repository; + +import static org.junit.Assert.assertThat; + +import org.baeldung.boot.DemoApplicationIntegrationTest; +import org.baeldung.boot.model.Foo; + +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.is; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class FooRepositoryIntegrationTest extends DemoApplicationIntegrationTest { + @Autowired + private FooRepository fooRepository; + + @Before + public void setUp() { + fooRepository.save(new Foo("Foo")); + fooRepository.save(new Foo("Bar")); + } + + @Test + public void testFindByName() { + Foo foo = fooRepository.findByName("Bar"); + assertThat(foo, notNullValue()); + assertThat(foo.getId(), is(2)); + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/HibernateSessionIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/HibernateSessionIntegrationTest.java new file mode 100644 index 0000000000..be992bcc36 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/HibernateSessionIntegrationTest.java @@ -0,0 +1,32 @@ +package org.baeldung.boot.repository; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import org.baeldung.boot.ApplicationIntegrationTest; +import org.baeldung.boot.model.Foo; +import org.baeldung.session.exception.repository.FooRepository; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.TestPropertySource; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@TestPropertySource("classpath:exception-hibernate.properties") +public class HibernateSessionIntegrationTest extends ApplicationIntegrationTest { + @Autowired + private FooRepository fooRepository; + + @Test + public void whenSavingWithCurrentSession_thenThrowNoException() { + Foo foo = new Foo("Exception Solved"); + fooRepository.save(foo); + foo = null; + foo = fooRepository.get(1); + + assertThat(foo, notNullValue()); + assertThat(foo.getId(), is(1)); + assertThat(foo.getName(), is("Exception Solved")); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/NoHibernateSessionIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/NoHibernateSessionIntegrationTest.java new file mode 100644 index 0000000000..55b7fa7216 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/boot/repository/NoHibernateSessionIntegrationTest.java @@ -0,0 +1,21 @@ +package org.baeldung.boot.repository; + +import org.baeldung.boot.ApplicationIntegrationTest; +import org.baeldung.boot.model.Foo; +import org.baeldung.session.exception.repository.FooRepository; +import org.hibernate.HibernateException; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class NoHibernateSessionIntegrationTest extends ApplicationIntegrationTest { + @Autowired + private FooRepository fooRepository; + + @Test(expected = HibernateException.class) + public void whenSavingWithoutCurrentSession_thenThrowException() { + Foo foo = new Foo("Exception Thrown"); + fooRepository.save(foo); + } +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/client/DetailsServiceClientIntegrationTest.java b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/client/DetailsServiceClientIntegrationTest.java new file mode 100644 index 0000000000..5627855aa3 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/java/org/baeldung/client/DetailsServiceClientIntegrationTest.java @@ -0,0 +1,46 @@ +package org.baeldung.client; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +@RunWith(SpringRunner.class) +@RestClientTest(DetailsServiceClient.class) +public class DetailsServiceClientIntegrationTest { + + @Autowired + private DetailsServiceClient client; + + @Autowired + private MockRestServiceServer server; + + @Autowired + private ObjectMapper objectMapper; + + @Before + public void setUp() throws Exception { + String detailsString = objectMapper.writeValueAsString(new Details("John Smith", "john")); + this.server.expect(requestTo("/john/details")).andRespond(withSuccess(detailsString, MediaType.APPLICATION_JSON)); + } + + @Test + public void whenCallingGetUserDetails_thenClientExecutesCorrectCall() throws Exception { + + Details details = this.client.getUserDetails("john"); + + assertThat(details.getLogin()).isEqualTo("john"); + assertThat(details.getName()).isEqualTo("John Smith"); + + } + +} diff --git a/spring-custom-aop/spring-custom-aop/src/test/resources/application.properties b/spring-custom-aop/spring-custom-aop/src/test/resources/application.properties new file mode 100644 index 0000000000..0e6cb86bc5 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/resources/application.properties @@ -0,0 +1,5 @@ +spring.mail.host=localhost +spring.mail.port=8025 +spring.mail.properties.mail.smtp.auth=false + +security.basic.enabled=false \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/resources/exception-hibernate.properties b/spring-custom-aop/spring-custom-aop/src/test/resources/exception-hibernate.properties new file mode 100644 index 0000000000..cde746acb9 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/resources/exception-hibernate.properties @@ -0,0 +1,2 @@ +spring.profiles.active=exception +spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext diff --git a/spring-custom-aop/spring-custom-aop/src/test/resources/exception.properties b/spring-custom-aop/spring-custom-aop/src/test/resources/exception.properties new file mode 100644 index 0000000000..c55e415a3a --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/resources/exception.properties @@ -0,0 +1,6 @@ +# Security +security.user.name=admin +security.user.password=password + +spring.dao.exceptiontranslation.enabled=false +spring.profiles.active=exception \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/resources/import.sql b/spring-custom-aop/spring-custom-aop/src/test/resources/import.sql new file mode 100644 index 0000000000..a382410271 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/resources/import.sql @@ -0,0 +1 @@ +Insert into Foo values(1,'Foo_Name'); \ No newline at end of file diff --git a/spring-custom-aop/spring-custom-aop/src/test/resources/org/baeldung/boot/expected.json b/spring-custom-aop/spring-custom-aop/src/test/resources/org/baeldung/boot/expected.json new file mode 100644 index 0000000000..f5409421a6 --- /dev/null +++ b/spring-custom-aop/spring-custom-aop/src/test/resources/org/baeldung/boot/expected.json @@ -0,0 +1,4 @@ +{ + "id":3, + "name":"Foo_Name_3" +} \ No newline at end of file From c817aec2dc5303da4aca06bd222b6c21704cee24 Mon Sep 17 00:00:00 2001 From: dhruba619 Date: Sun, 2 Apr 2017 21:20:31 +0530 Subject: [PATCH 240/291] BAEL-716 Junit vs testng improvement updated formatting --- .../com/baeldung/junit4vstestng/SortedTests.java | 15 ++++++--------- .../src/test/java/baeldung/com/PriorityTest.java | 6 ++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java b/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java index 1fa4a4e61b..fe0ec1469c 100644 --- a/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java +++ b/core-java/src/test/java/com/baeldung/junit4vstestng/SortedTests.java @@ -6,20 +6,17 @@ import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; - @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SortedTests { - + @Test - public void a_givenString_whenChangedtoInt_thenTrue(){ - assertTrue( - Integer.valueOf("10") instanceof Integer); + public void a_givenString_whenChangedtoInt_thenTrue() { + assertTrue(Integer.valueOf("10") instanceof Integer); } - + @Test - public void b_givenInt_whenChangedtoString_thenTrue(){ - assertTrue( - String.valueOf(10) instanceof String); + public void b_givenInt_whenChangedtoString_thenTrue() { + assertTrue(String.valueOf(10) instanceof String); } } diff --git a/testng/src/test/java/baeldung/com/PriorityTest.java b/testng/src/test/java/baeldung/com/PriorityTest.java index 34f2d6fe47..d014d5c920 100644 --- a/testng/src/test/java/baeldung/com/PriorityTest.java +++ b/testng/src/test/java/baeldung/com/PriorityTest.java @@ -10,14 +10,12 @@ public class PriorityTest { @Test(priority = 1) public void givenString_whenChangedToInt_thenCorrect() { - Assert.assertTrue( - Integer.valueOf(testString) instanceof Integer); + Assert.assertTrue(Integer.valueOf(testString) instanceof Integer); } @Test(priority = 2) public void givenInt_whenChangedToString_thenCorrect() { - Assert.assertTrue( - String.valueOf(testInt) instanceof String); + Assert.assertTrue(String.valueOf(testInt) instanceof String); } } From d361c91ed3f9e2216c441f61be820b19f0748dfa Mon Sep 17 00:00:00 2001 From: ahamedm Date: Sun, 2 Apr 2017 22:57:45 +0400 Subject: [PATCH 241/291] BAEL-696 Implement OR in the REST API Query Language - Alternate Impl (#1576) * Dependency Injection Types, XML-Config, Java-Config, Test Classes * Formatting done with Formatter Configuration in Eclipse * REST Query Lang - Adv Search Ops - Improvement - C1 * REST Query Lang - Adv Search Ops - Improvement - C2 * BAEL-696 Code formatting * REST Query Lang - Adv Search Ops - Improvement - C3 * BAEL-696 Formatting * OR operation with PostFix Expression * Revert the changes done for PostFix Expr * Merged from Upstream * Remove Sorting of Predicates * REST Query Lang - Adv Search Ops - Improvement - C5 --- .../dao/GenericSpecificationsBuilder.java | 63 ++++++++++----- .../dao/UserSpecificationsBuilder.java | 7 +- .../web/controller/UserController.java | 26 +++++-- .../org/baeldung/web/util/CriteriaParser.java | 76 +++++++++++++++++++ .../baeldung/web/util/SearchOperation.java | 8 ++ .../baeldung/web/util/SpecSearchCriteria.java | 21 +++++ .../JPASpecificationIntegrationTest.java | 29 +++++-- .../query/JPASpecificationLiveTest.java | 51 ++++++++++--- 8 files changed, 233 insertions(+), 48 deletions(-) create mode 100644 spring-security-rest-full/src/main/java/org/baeldung/web/util/CriteriaParser.java diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java index 45c015f233..64bab9a435 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/GenericSpecificationsBuilder.java @@ -1,7 +1,9 @@ package org.baeldung.persistence.dao; import java.util.ArrayList; -import java.util.Comparator; +import java.util.Collections; +import java.util.Deque; +import java.util.LinkedList; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -11,7 +13,7 @@ import org.baeldung.web.util.SpecSearchCriteria; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specifications; -public class GenericSpecificationsBuilder { +public class GenericSpecificationsBuilder { private final List params; @@ -19,11 +21,11 @@ public class GenericSpecificationsBuilder { this.params = new ArrayList<>(); } - public final GenericSpecificationsBuilder with(final String key, final String operation, final Object value, final String prefix, final String suffix) { + public final GenericSpecificationsBuilder with(final String key, final String operation, final Object value, final String prefix, final String suffix) { return with(null, key, operation, value, prefix, suffix); } - public final GenericSpecificationsBuilder with(final String precedenceIndicator, final String key, final String operation, final Object value, final String prefix, final String suffix) { + public final GenericSpecificationsBuilder with(final String precedenceIndicator, final String key, final String operation, final Object value, final String prefix, final String suffix) { SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); if (op != null) { if (op == SearchOperation.EQUALITY) // the operation may be complex operation @@ -44,33 +46,54 @@ public class GenericSpecificationsBuilder { return this; } - public Specification build(Function> converter) { + public Specification build(Function> converter) { if (params.size() == 0) { return null; } - params.sort(Comparator.comparing(SpecSearchCriteria::isOrPredicate)); - - final List> specs = params - .stream() - .map(converter) - .collect(Collectors.toCollection(ArrayList::new)); + final List> specs = params.stream() + .map(converter) + .collect(Collectors.toCollection(ArrayList::new)); Specification result = specs.get(0); for (int idx = 1; idx < specs.size(); idx++) { - result = params - .get(idx) - .isOrPredicate() - ? Specifications - .where(result) - .or(specs.get(idx)) - : Specifications - .where(result) - .and(specs.get(idx)); + result = params.get(idx) + .isOrPredicate() + ? Specifications.where(result) + .or(specs.get(idx)) + : Specifications.where(result) + .and(specs.get(idx)); } return result; } + public Specification build(Deque postFixedExprStack, Function> converter) { + + Deque> specStack = new LinkedList<>(); + + Collections.reverse((List) postFixedExprStack); + + while (!postFixedExprStack.isEmpty()) { + Object mayBeOperand = postFixedExprStack.pop(); + + if (!(mayBeOperand instanceof String)) { + specStack.push(converter.apply((SpecSearchCriteria) mayBeOperand)); + } else { + Specification operand1 = specStack.pop(); + Specification operand2 = specStack.pop(); + if (mayBeOperand.equals(SearchOperation.AND_OPERATOR)) + specStack.push(Specifications.where(operand1) + .and(operand2)); + else if (mayBeOperand.equals(SearchOperation.OR_OPERATOR)) + specStack.push(Specifications.where(operand1) + .or(operand2)); + } + + } + return specStack.pop(); + + } + } diff --git a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java index bbcb521241..a8e5b96acb 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/persistence/dao/UserSpecificationsBuilder.java @@ -1,7 +1,6 @@ package org.baeldung.persistence.dao; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import org.baeldung.persistence.model.User; @@ -24,7 +23,7 @@ public final class UserSpecificationsBuilder { return with(null, key, operation, value, prefix, suffix); } - public final UserSpecificationsBuilder with(final String precedenceIndicator, final String key, final String operation, final Object value, final String prefix, final String suffix) { + public final UserSpecificationsBuilder with(final String orPredicate, final String key, final String operation, final Object value, final String prefix, final String suffix) { SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); if (op != null) { if (op == SearchOperation.EQUALITY) { // the operation may be complex operation @@ -39,7 +38,7 @@ public final class UserSpecificationsBuilder { op = SearchOperation.STARTS_WITH; } } - params.add(new SpecSearchCriteria(precedenceIndicator, key, op, value)); + params.add(new SpecSearchCriteria(orPredicate, key, op, value)); } return this; } @@ -49,8 +48,6 @@ public final class UserSpecificationsBuilder { if (params.size() == 0) return null; - params.sort(Comparator.comparing(SpecSearchCriteria::isOrPredicate)); - Specification result = new UserSpecification(params.get(0)); for (int i = 1; i < params.size(); i++) { diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java index 4c21d9836d..8953a52a1b 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/UserController.java @@ -5,14 +5,17 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.baeldung.persistence.dao.GenericSpecificationsBuilder; import org.baeldung.persistence.dao.IUserDAO; import org.baeldung.persistence.dao.MyUserPredicatesBuilder; import org.baeldung.persistence.dao.MyUserRepository; import org.baeldung.persistence.dao.UserRepository; +import org.baeldung.persistence.dao.UserSpecification; import org.baeldung.persistence.dao.UserSpecificationsBuilder; import org.baeldung.persistence.dao.rsql.CustomRsqlVisitor; import org.baeldung.persistence.model.MyUser; import org.baeldung.persistence.model.User; +import org.baeldung.web.util.CriteriaParser; import org.baeldung.web.util.SearchCriteria; import org.baeldung.web.util.SearchOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -74,9 +77,8 @@ public class UserController { @ResponseBody public List findAllBySpecification(@RequestParam(value = "search") String search) { UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - String operationSetExper = Joiner - .on("|") - .join(SearchOperation.SIMPLE_OPERATION_SET); + String operationSetExper = Joiner.on("|") + .join(SearchOperation.SIMPLE_OPERATION_SET); Pattern pattern = Pattern.compile("(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); Matcher matcher = pattern.matcher(search + ","); while (matcher.find()) { @@ -94,12 +96,24 @@ public class UserController { return dao.findAll(spec); } + @GetMapping(value = "/users/spec/adv") + @ResponseBody + public List findAllByAdvPredicate(@RequestParam(value = "search") String search) { + Specification spec = resolveSpecificationFromInfixExpr(search); + return dao.findAll(spec); + } + + protected Specification resolveSpecificationFromInfixExpr(String searchParameters) { + CriteriaParser parser = new CriteriaParser(); + GenericSpecificationsBuilder specBuilder = new GenericSpecificationsBuilder<>(); + return specBuilder.build(parser.parse(searchParameters), UserSpecification::new); + } + protected Specification resolveSpecification(String searchParameters) { UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - String operationSetExper = Joiner - .on("|") - .join(SearchOperation.SIMPLE_OPERATION_SET); + String operationSetExper = Joiner.on("|") + .join(SearchOperation.SIMPLE_OPERATION_SET); Pattern pattern = Pattern.compile("(\\p{Punct}?)(\\w+?)(" + operationSetExper + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?),"); Matcher matcher = pattern.matcher(searchParameters + ","); while (matcher.find()) { diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/CriteriaParser.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/CriteriaParser.java new file mode 100644 index 0000000000..eabc938bce --- /dev/null +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/CriteriaParser.java @@ -0,0 +1,76 @@ +package org.baeldung.web.util; + +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.base.Joiner; + +public class CriteriaParser { + + private static Map ops; + + private static Pattern SpecCriteraRegex = Pattern.compile("^(\\w+?)(" + Joiner.on("|") + .join(SearchOperation.SIMPLE_OPERATION_SET) + ")(\\p{Punct}?)(\\w+?)(\\p{Punct}?)$"); + + private enum Operator { + OR(1), AND(2); + final int precedence; + + Operator(int p) { + precedence = p; + } + } + + static { + Map tempMap = new HashMap<>(); + tempMap.put("AND", Operator.AND); + tempMap.put("OR", Operator.OR); + tempMap.put("or", Operator.OR); + tempMap.put("and", Operator.AND); + + ops = Collections.unmodifiableMap(tempMap); + } + + private static boolean isHigerPrecedenceOperator(String currOp, String prevOp) { + return (ops.containsKey(prevOp) && ops.get(prevOp).precedence >= ops.get(currOp).precedence); + } + + public Deque parse(String searchParam) { + + Deque output = new LinkedList<>(); + Deque stack = new LinkedList<>(); + + for (String token : searchParam.split("\\s+")) { + if (ops.containsKey(token)) { + while (!stack.isEmpty() && isHigerPrecedenceOperator(token, stack.peek())) + output.push(stack.pop() + .equalsIgnoreCase(SearchOperation.OR_OPERATOR) ? SearchOperation.OR_OPERATOR : SearchOperation.AND_OPERATOR); + stack.push(token.equalsIgnoreCase(SearchOperation.OR_OPERATOR) ? SearchOperation.OR_OPERATOR : SearchOperation.AND_OPERATOR); + } else if (token.equals(SearchOperation.LEFT_PARANTHESIS)) { + stack.push(SearchOperation.LEFT_PARANTHESIS); + } else if (token.equals(SearchOperation.RIGHT_PARANTHESIS)) { + while (!stack.peek() + .equals(SearchOperation.LEFT_PARANTHESIS)) + output.push(stack.pop()); + stack.pop(); + } else { + + Matcher matcher = SpecCriteraRegex.matcher(token); + while (matcher.find()) { + output.push(new SpecSearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4), matcher.group(5))); + } + } + } + + while (!stack.isEmpty()) + output.push(stack.pop()); + + return output; + } + +} diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java index fa09662201..db2c0133cf 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SearchOperation.java @@ -9,6 +9,14 @@ public enum SearchOperation { public static final String ZERO_OR_MORE_REGEX = "*"; + public static final String OR_OPERATOR = "OR"; + + public static final String AND_OPERATOR = "AND"; + + public static final String LEFT_PARANTHESIS = "("; + + public static final String RIGHT_PARANTHESIS = ")"; + public static SearchOperation getSimpleOperation(final char input) { switch (input) { case ':': diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java index 6b37fb579c..3435ff3342 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SpecSearchCriteria.java @@ -26,6 +26,27 @@ public class SpecSearchCriteria { this.value = value; } + public SpecSearchCriteria(String key, String operation, String prefix, String value, String suffix) { + SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0)); + if (op != null) { + if (op == SearchOperation.EQUALITY) { // the operation may be complex operation + final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX); + + if (startWithAsterisk && endWithAsterisk) { + op = SearchOperation.CONTAINS; + } else if (startWithAsterisk) { + op = SearchOperation.ENDS_WITH; + } else if (endWithAsterisk) { + op = SearchOperation.STARTS_WITH; + } + } + } + this.key = key; + this.operation = op; + this.value = value; + } + public String getKey() { return key; } diff --git a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java index 244e19db90..d9ae95c876 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationIntegrationTest.java @@ -6,6 +6,7 @@ import org.baeldung.persistence.dao.UserSpecification; import org.baeldung.persistence.dao.UserSpecificationsBuilder; import org.baeldung.persistence.model.User; import org.baeldung.spring.PersistenceConfig; +import org.baeldung.web.util.CriteriaParser; import org.baeldung.web.util.SearchOperation; import org.baeldung.web.util.SpecSearchCriteria; import org.junit.Before; @@ -82,12 +83,12 @@ public class JPASpecificationIntegrationTest { public void givenFirstOrLastName_whenGettingListOfUsers_thenCorrect() { UserSpecificationsBuilder builder = new UserSpecificationsBuilder(); - SpecSearchCriteria spec = new SpecSearchCriteria("'", "firstName", SearchOperation.EQUALITY, "john"); - SpecSearchCriteria spec1 = new SpecSearchCriteria("lastName", SearchOperation.EQUALITY, "doe"); + SpecSearchCriteria spec = new SpecSearchCriteria("firstName", SearchOperation.EQUALITY, "john"); + SpecSearchCriteria spec1 = new SpecSearchCriteria("'","lastName", SearchOperation.EQUALITY, "doe"); List results = repository.findAll(builder - .with(spec1) .with(spec) + .with(spec1) .build()); assertThat(results, hasSize(2)); @@ -96,11 +97,25 @@ public class JPASpecificationIntegrationTest { } @Test - public void givenFirstOrLastNameGenericBuilder_whenGettingListOfUsers_thenCorrect() { - GenericSpecificationsBuilder builder = new GenericSpecificationsBuilder(); + public void givenFirstOrLastNameAndAgeGenericBuilder_whenGettingListOfUsers_thenCorrect() { + GenericSpecificationsBuilder builder = new GenericSpecificationsBuilder<>(); Function> converter = UserSpecification::new; - builder.with("'", "firstName", ":", "john", null, null); - builder.with(null, "lastName", ":", "doe", null, null); + + CriteriaParser parser=new CriteriaParser(); + List results = repository.findAll(builder.build(parser.parse("( lastName:doe OR firstName:john ) AND age:22"), converter)); + + assertThat(results, hasSize(1)); + assertThat(userJohn, isIn(results)); + assertThat(userTom, not(isIn(results))); + } + + @Test + public void givenFirstOrLastNameGenericBuilder_whenGettingListOfUsers_thenCorrect() { + GenericSpecificationsBuilder builder = new GenericSpecificationsBuilder<>(); + Function> converter = UserSpecification::new; + + builder.with("firstName", ":", "john", null, null); + builder.with("'", "lastName", ":", "doe", null, null); List results = repository.findAll(builder.build(converter)); diff --git a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java index 55fde80add..70787266d8 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/persistence/query/JPASpecificationLiveTest.java @@ -47,8 +47,9 @@ public class JPASpecificationLiveTest { @Test public void givenFirstOrLastName_whenGettingListOfUsers_thenCorrect() { - final Response response = givenAuth().get(EURL_PREFIX + "'firstName:john,lastName:doe"); - final String result = response.body().asString(); + final Response response = givenAuth().get(EURL_PREFIX + "firstName:john,'lastName:doe"); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertTrue(result.contains(userTom.getEmail())); } @@ -56,7 +57,8 @@ public class JPASpecificationLiveTest { @Test public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "firstName:john,lastName:doe"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertFalse(result.contains(userTom.getEmail())); @@ -65,7 +67,8 @@ public class JPASpecificationLiveTest { @Test public void givenFirstNameInverse_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "firstName!john"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userTom.getEmail())); assertFalse(result.contains(userJohn.getEmail())); @@ -74,7 +77,8 @@ public class JPASpecificationLiveTest { @Test public void givenMinAge_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "age>25"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userTom.getEmail())); assertFalse(result.contains(userJohn.getEmail())); @@ -83,7 +87,8 @@ public class JPASpecificationLiveTest { @Test public void givenFirstNamePrefix_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "firstName:jo*"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertFalse(result.contains(userTom.getEmail())); @@ -92,7 +97,8 @@ public class JPASpecificationLiveTest { @Test public void givenFirstNameSuffix_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "firstName:*n"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertFalse(result.contains(userTom.getEmail())); @@ -101,7 +107,8 @@ public class JPASpecificationLiveTest { @Test public void givenFirstNameSubstring_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "firstName:*oh*"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertFalse(result.contains(userTom.getEmail())); @@ -110,13 +117,37 @@ public class JPASpecificationLiveTest { @Test public void givenAgeRange_whenGettingListOfUsers_thenCorrect() { final Response response = givenAuth().get(URL_PREFIX + "age>20,age<25"); - final String result = response.body().asString(); + final String result = response.body() + .asString(); assertTrue(result.contains(userJohn.getEmail())); assertFalse(result.contains(userTom.getEmail())); } + private final String ADV_URL_PREFIX = "http://localhost:8082/spring-security-rest-full/auth/users/spec/adv?search="; + + @Test + public void givenFirstOrLastName_whenGettingAdvListOfUsers_thenCorrect() { + final Response response = givenAuth().get(ADV_URL_PREFIX + "firstName:john OR lastName:doe"); + final String result = response.body() + .asString(); + assertTrue(result.contains(userJohn.getEmail())); + assertTrue(result.contains(userTom.getEmail())); + } + + @Test + public void givenFirstOrFirstNameAndAge_whenGettingAdvListOfUsers_thenCorrect() { + final Response response = givenAuth().get(ADV_URL_PREFIX + "( firstName:john OR firstName:tom ) AND age>22"); + final String result = response.body() + .asString(); + assertFalse(result.contains(userJohn.getEmail())); + assertTrue(result.contains(userTom.getEmail())); + } + private final RequestSpecification givenAuth() { - return RestAssured.given().auth().preemptive().basic("user1", "user1Pass"); + return RestAssured.given() + .auth() + .preemptive() + .basic("user1", "user1Pass"); } } From 54615ddd11f87be945780b5437d7bda060ed5fb5 Mon Sep 17 00:00:00 2001 From: Diane Duan Date: Mon, 3 Apr 2017 03:28:36 +0800 Subject: [PATCH 242/291] BAEL-640: Guide to Mathematical Operations with Guava (#1390) * Guava IntMath tests * Guava DoubleMath test * break down testDoubleMath() --- .../org/baeldung/guava/GuavaMathTest.java | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 guava/src/test/java/org/baeldung/guava/GuavaMathTest.java diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java b/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java new file mode 100644 index 0000000000..d0c551032c --- /dev/null +++ b/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java @@ -0,0 +1,192 @@ +package org.baeldung.guava; + +import com.google.common.math.DoubleMath; +import com.google.common.math.IntMath; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.math.BigInteger; +import java.math.RoundingMode; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class GuavaMathTest { + @Test + public void testIntMathAdd() { + try { + IntMath.checkedAdd(Integer.MAX_VALUE, 1); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + try { + IntMath.checkedAdd(Integer.MIN_VALUE, -1); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + int result1 = IntMath.checkedAdd(2, 1); + assertThat(result1, equalTo(3)); + + int result2 = IntMath.saturatedAdd(Integer.MAX_VALUE, 100); + assertThat(result2, equalTo(Integer.MAX_VALUE)); + + int result3 = IntMath.saturatedAdd(Integer.MIN_VALUE, -100); + assertThat(result3, equalTo(Integer.MIN_VALUE)); + } + + @Test + public void testIntMathSubtract() { + try { + IntMath.checkedSubtract(Integer.MIN_VALUE, 1); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + try { + IntMath.checkedSubtract(Integer.MAX_VALUE, -1); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + }; + + int result1 = IntMath.checkedSubtract(200, 100); + assertThat(result1, equalTo(100)); + + int result2 = IntMath.saturatedSubtract(Integer.MIN_VALUE, 1); + assertThat(result2, equalTo(Integer.MIN_VALUE)); + + int result3 = IntMath.saturatedSubtract(Integer.MAX_VALUE, -1); + assertThat(result3, equalTo(Integer.MAX_VALUE)); + } + + @Test + public void testIntMathMultiply() { + try { + IntMath.checkedMultiply(Integer.MAX_VALUE, 2); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + try { + IntMath.checkedMultiply(Integer.MIN_VALUE, 2); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + int result1 = IntMath.checkedMultiply(21, 3); + assertThat(result1, equalTo(63)); + + int result2 = IntMath.saturatedMultiply(Integer.MAX_VALUE, 2); + assertThat(result2, equalTo(Integer.MAX_VALUE)); + + int result3 = IntMath.saturatedMultiply(Integer.MIN_VALUE, 2); + assertThat(result3, equalTo(Integer.MIN_VALUE)); + } + + @Test + public void testIntMathPow() { + try { + IntMath.checkedPow(Integer.MAX_VALUE, 2); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + try { + IntMath.checkedPow(Integer.MIN_VALUE, 3); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + + int result1 = IntMath.saturatedPow(3, 3); + assertThat(result1, equalTo(27)); + + int result2 = IntMath.saturatedPow(Integer.MAX_VALUE, 2); + assertThat(result2, equalTo(Integer.MAX_VALUE)); + + int result3 = IntMath.saturatedPow(Integer.MIN_VALUE, 3); + assertThat(result3, equalTo(Integer.MIN_VALUE)); + } + + @Test + public void testIntMathRound() { + int result1 = IntMath.divide(3, 2, RoundingMode.DOWN); + assertThat(result1, equalTo(1)); + int result2 = IntMath.divide(3, 2, RoundingMode.UP); + assertThat(result2, equalTo(2)); + + int result3 = IntMath.log2(5, RoundingMode.FLOOR); + assertThat(result3, equalTo(2)); + int result4 = IntMath.log2(5, RoundingMode.CEILING); + assertThat(result4, equalTo(3)); + + int result5 = IntMath.log10(11, RoundingMode.HALF_UP); + assertThat(result5, equalTo(1)); + + int result6 = IntMath.sqrt(4, RoundingMode.UNNECESSARY); + assertThat(result6, equalTo(2)); + try { + IntMath.sqrt(5, RoundingMode.UNNECESSARY); + assertTrue(false); + } catch (ArithmeticException e) { + assertTrue(true); + } + } + + @Test + public void testIntMathAdditionalFunctions() { + int result1 = IntMath.gcd(15, 20); + assertThat(result1, equalTo(5)); + + int result2 = IntMath.mod(8, 3); + assertThat(result2, equalTo(2)); + + boolean result3 = IntMath.isPowerOfTwo(8); + assertTrue(result3); + boolean result4 = IntMath.isPowerOfTwo(9); + assertFalse(result4); + + int result5 = IntMath.factorial(4); + assertThat(result5, equalTo(24)); + + int result6 = IntMath.binomial(7, 3); + assertThat(result6, equalTo(35)); + } + + @Test + public void should_detect_integer() { + boolean result1 = DoubleMath.isMathematicalInteger(2.0); + assertThat(result1, equalTo(true)); + boolean result2 = DoubleMath.isMathematicalInteger(2.1); + assertThat(result2, equalTo(false)); + } + + @Test + public void should_round_to_integer_types() { + int result3 = DoubleMath.roundToInt(2.5, RoundingMode.DOWN); + assertThat(result3, equalTo(2)); + + long result4 = DoubleMath.roundToLong(2.5, RoundingMode.HALF_UP); + assertThat(result4, equalTo(3L)); + + BigInteger result5 = DoubleMath.roundToBigInteger(2.5, RoundingMode.UP); + assertThat(result5, equalTo(new BigInteger("3"))); + } + + @Test + public void should_calculate_log_2() { + int result6 = DoubleMath.log2(10, RoundingMode.UP); + assertThat(result6, equalTo(4)); + } +} \ No newline at end of file From 09329512cd24d1948b2d1aa98cfbfee3be31f1e8 Mon Sep 17 00:00:00 2001 From: buddhini81 Date: Mon, 3 Apr 2017 02:04:46 +0530 Subject: [PATCH 243/291] Modifications to the JavaEEAnnotationsSample application (#1522) * Delete the class As it is not relevant for the example * Update AccountServlet.java Changes made in doPost method. * Update UploadCustomerDocumentsServlet.java Changes made in doPost method * README file added * Fix error - add missing import --- .../JavaEEAnnotationsSample/README.txt | 67 +++++++++++++++++++ .../javaeeannotations/AccountServlet.java | 10 +-- .../DepositRequestListener.java | 20 ------ .../UploadCustomerDocumentsServlet.java | 5 ++ 4 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt delete mode 100644 jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt new file mode 100644 index 0000000000..063856b2be --- /dev/null +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt @@ -0,0 +1,67 @@ +About the application +--------------------- +This application demonstrates the usage of JavaEE Web Annotations. + + +Contents of the application +--------------------------- +1. AccountServlet.java - Demonstrates the @WebServlet and @ServletSecurity annotation. + +NOTES: @WebServlet annotation designates the AccountServlet class as a Servlet component. + The usage of its parameters 'urlPatterns' & 'initParams' can be observed. + An initialization parameter 'type' is being set to denote the type of the bank account. + + @ServletSecurity annotation imposes security constraints on the AccountServlet based on + the tomcat-users.xml (this code assumes there is a role 'admin' in your tomcat-users.xml) + +N.B : To see @ServletSecurity annotation in action, please uncomment the annotation code + for @ServletSecurity. + + +2. BankAppServletContextListener.java - Demonstrates the @WebListener annotation for denoting a class as a ServletContextListener. + +NOTES: Sets a Servlet context attribute ATTR_DEFAULT_LANGUAGE to 'english' on web application start up, + which can then be used throughout the application. + + +3. LogInFilter.java - Demonstrates the @WebFilter annotation. + +NOTES: @WebFilter annotation designates the LogInFilter class as a Filter component. + It filters all requests to the bank account servlet and redirects them to + the login page. + +N.B : To see @WebFilter annotation in action, please uncomment the annotation code for @WebFilter. + + +4. UploadCustomerDocumentsServlet.java - Demonstrates the @MultipartConfig annotation. + +NOTES: @MultipartConfig anotation designates the UploadCustomerDocumentsServlet Servlet component, + to handle multipart/form-data requests. + To see it in action, deploy the web application an access the url: http://:/JavaEEAnnotationsSample/upload.jsp + Once you upload a file from here, it will get uploaded to D:/custDocs (assuming such a folder exists). + + +5. index.jsp - This is the welcome page. + +NOTES: You can enter a deposit amount here and click on the 'Deposit' button to see the AccountServlet in action. + +6. login.jsp - All requests to the AccountServlet are redirected to this page, if the LogInFilter is imposed. + +7. upload.jsp - Demonstrates the usage of handling multipart/form-data requests by the UploadCustomerDocumentsServlet. + + +Building and Running the application +------------------------------------ +To build the application: + +1. Open the project in eclipse +2. Right click on it in eclispe and choose Run As > Maven build +3. Give 'clean install' under Goals +4. This should build the WAR file of the application + +To run the application: + +1. Right click on the project +2. Run as > Run on Server +3. This will start you Tomcat server and deploy the application (Provided that you have configured Tomcat in your eclipse) +4. You should now be able to access the url : http://:/JavaEEAnnotationsSample diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java index e24eb307bb..a8ed74984b 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java @@ -36,19 +36,15 @@ public class AccountServlet extends javax.servlet.http.HttpServlet { } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + double accountBalance = 1000d; - double interestRate = Double.parseDouble(request.getAttribute("interest").toString()); - String paramDepositAmt = request.getParameter("dep"); double depositAmt = Double.parseDouble(paramDepositAmt); accountBalance = accountBalance + depositAmt; - + PrintWriter writer = response.getWriter(); - writer.println(" Balance of " + accountType + " account is: " + - accountBalance + "
This account bares an interest rate of " + interestRate + - " % "); + writer.println(" Balance of " + accountType + " account is: " + accountBalance + ""); writer.flush(); - } } diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java deleted file mode 100644 index f361c84b97..0000000000 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/DepositRequestListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.baeldung.javaeeannotations; - -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; -import javax.servlet.annotation.WebListener; -import javax.servlet.http.HttpServletRequest; - -@WebListener -public class DepositRequestListener implements ServletRequestListener { - - public void requestDestroyed(ServletRequestEvent event) { - - } - - public void requestInitialized(ServletRequestEvent evet) { - HttpServletRequest req = (HttpServletRequest)evet.getServletRequest(); - req.setAttribute("interest", new Double(10)); - } - -} diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java index 3a139ad7cc..28922dba46 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java @@ -1,6 +1,7 @@ package com.baeldung.javaeeannotations; import java.io.IOException; +import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; @@ -24,6 +25,10 @@ public class UploadCustomerDocumentsServlet extends HttpServlet { for (Part part : request.getParts()) { part.write("myFile"); } + + PrintWriter writer = response.getWriter(); + writer.println("File uploaded successfully!"); + writer.flush(); } } From 44e63c68f2520cafd3bd73f703c9500f994eb1ba Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Sun, 2 Apr 2017 23:54:28 +0200 Subject: [PATCH 244/291] Bael 769 javers (#1543) * BAEL-769 code for javers article * BAEL-769 add more examples --- libraries/pom.xml | 6 + .../java/com/baeldung/javers/Address.java | 11 ++ .../main/java/com/baeldung/javers/Person.java | 27 +++++ .../baeldung/javers/PersonWithAddress.java | 40 +++++++ .../java/com/baeldung/javers/JaversTest.java | 113 ++++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 libraries/src/main/java/com/baeldung/javers/Address.java create mode 100644 libraries/src/main/java/com/baeldung/javers/Person.java create mode 100644 libraries/src/main/java/com/baeldung/javers/PersonWithAddress.java create mode 100644 libraries/src/test/java/com/baeldung/javers/JaversTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 71d0e76c8a..11295230b4 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -67,6 +67,11 @@ jsonassert ${jsonassert.version} + + org.javers + javers-core + ${javers.version} + @@ -78,6 +83,7 @@ 3.21.0-GA 3.6.2 1.5.0 + 3.1.0 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/javers/Address.java b/libraries/src/main/java/com/baeldung/javers/Address.java new file mode 100644 index 0000000000..14f5907ef6 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/javers/Address.java @@ -0,0 +1,11 @@ +package com.baeldung.javers; + + +public class Address { + private String country; + + public Address(String country) { + this.country = country; + } + +} diff --git a/libraries/src/main/java/com/baeldung/javers/Person.java b/libraries/src/main/java/com/baeldung/javers/Person.java new file mode 100644 index 0000000000..c53a09358b --- /dev/null +++ b/libraries/src/main/java/com/baeldung/javers/Person.java @@ -0,0 +1,27 @@ +package com.baeldung.javers; + +public class Person { + private Integer id; + private String name; + + public Person(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/javers/PersonWithAddress.java b/libraries/src/main/java/com/baeldung/javers/PersonWithAddress.java new file mode 100644 index 0000000000..0b4e33fcb5 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/javers/PersonWithAddress.java @@ -0,0 +1,40 @@ +package com.baeldung.javers; + + +import java.util.List; + +public class PersonWithAddress { + private Integer id; + private String name; + private List
address; + + public PersonWithAddress(Integer id, String name, List
address) { + this.id = id; + this.name = name; + this.address = address; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public List
getAddress() { + return address; + } + + public void setAddress(List
address) { + this.address = address; + } +} diff --git a/libraries/src/test/java/com/baeldung/javers/JaversTest.java b/libraries/src/test/java/com/baeldung/javers/JaversTest.java new file mode 100644 index 0000000000..e8e3e62e08 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/javers/JaversTest.java @@ -0,0 +1,113 @@ +package com.baeldung.javers; + + +import org.javers.common.collections.Lists; +import org.javers.core.Javers; +import org.javers.core.JaversBuilder; +import org.javers.core.diff.Diff; +import org.javers.core.diff.changetype.NewObject; +import org.javers.core.diff.changetype.ObjectRemoved; +import org.javers.core.diff.changetype.ValueChange; +import org.javers.core.diff.changetype.container.ListChange; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JaversTest { + + @Test + public void givenPersonObject_whenApplyModificationOnIt_thenShouldDetectChange() { + //given + Javers javers = JaversBuilder.javers().build(); + + Person person = new Person(1, "Michael Program"); + Person personAfterModification = new Person(1, "Michael Java"); + + //when + Diff diff = javers.compare(person, personAfterModification); + + //then + ValueChange change = diff.getChangesByType(ValueChange.class).get(0); + + assertThat(diff.getChanges()).hasSize(1); + assertThat(change.getPropertyName()).isEqualTo("name"); + assertThat(change.getLeft()).isEqualTo("Michael Program"); + assertThat(change.getRight()).isEqualTo("Michael Java"); + } + + + @Test + public void givenListOfPersons_whenCompare_ThenShouldDetectChanges() { + //given + Javers javers = JaversBuilder.javers().build(); + Person personThatWillBeRemoved = new Person(2, "Thomas Link"); + List oldList = Lists.asList(new Person(1, "Michael Program"), personThatWillBeRemoved); + List newList = Lists.asList(new Person(1, "Michael Not Program")); + + //when + Diff diff = javers.compareCollections(oldList, newList, Person.class); + + //then + assertThat(diff.getChanges()).hasSize(3); + + + ValueChange valueChange = diff.getChangesByType(ValueChange.class).get(0); + assertThat(valueChange.getPropertyName()).isEqualTo("name"); + assertThat(valueChange.getLeft()).isEqualTo("Michael Program"); + assertThat(valueChange.getRight()).isEqualTo("Michael Not Program"); + + ObjectRemoved objectRemoved = diff.getChangesByType(ObjectRemoved.class).get(0); + assertThat(objectRemoved.getAffectedObject().get().equals(personThatWillBeRemoved)).isTrue(); + + ListChange listChange = diff.getChangesByType(ListChange.class).get(0); + assertThat(listChange.getValueRemovedChanges().size()).isEqualTo(1); + + } + + @Test + public void givenListOfPerson_whenPersonHasNewAddress_thenDetectThatChange() { + //given + Javers javers = JaversBuilder.javers().build(); + + PersonWithAddress person = + new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England"))); + + PersonWithAddress personWithNewAddress = + new PersonWithAddress(1, "Tom", + Arrays.asList(new Address("England"), new Address("USA"))); + + + //when + Diff diff = javers.compare(person, personWithNewAddress); + List objectsByChangeType = diff.getObjectsByChangeType(NewObject.class); + + //then + assertThat(objectsByChangeType).hasSize(1); + assertThat(objectsByChangeType.get(0).equals(new Address("USA"))); + } + + @Test + public void givenListOfPerson_whenPersonRemovedAddress_thenDetectThatChange() { + //given + Javers javers = JaversBuilder.javers().build(); + + PersonWithAddress person = + new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England"))); + + PersonWithAddress personWithNewAddress = + new PersonWithAddress(1, "Tom", Collections.emptyList()); + + + //when + Diff diff = javers.compare(person, personWithNewAddress); + List objectsByChangeType = diff.getObjectsByChangeType(ObjectRemoved.class); + + //then + assertThat(objectsByChangeType).hasSize(1); + assertThat(objectsByChangeType.get(0).equals(new Address("England"))); + } +} From 77d270a4b1bf0f145083ba36e64a08281ef2392c Mon Sep 17 00:00:00 2001 From: lor6 Date: Mon, 3 Apr 2017 04:53:22 +0300 Subject: [PATCH 245/291] in memory dbs config (#1551) * in memory dbs config * small fix --- spring-data-rest/pom.xml | 22 ++++++- .../java/com/baeldung/config/DbConfig.java | 61 +++++++++++++++++++ .../java/com/baeldung/models/Address.java | 3 +- .../main/java/com/baeldung/models/Author.java | 3 +- .../main/java/com/baeldung/models/Book.java | 3 +- .../java/com/baeldung/models/Library.java | 3 +- .../resources/persistence-derby.properties | 8 +++ .../main/resources/persistence-h2.properties | 8 +++ .../resources/persistence-hsqldb.properties | 8 +++ .../resources/persistence-sqlite.properties | 4 ++ 10 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java create mode 100644 spring-data-rest/src/main/resources/persistence-derby.properties create mode 100644 spring-data-rest/src/main/resources/persistence-h2.properties create mode 100644 spring-data-rest/src/main/resources/persistence-hsqldb.properties create mode 100644 spring-data-rest/src/main/resources/persistence-sqlite.properties diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index 1e1ec02e96..91b6d61878 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 1.5.2.RELEASE @@ -41,6 +41,26 @@ com.h2database h2 + + org.springframework.boot diff --git a/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java b/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java new file mode 100644 index 0000000000..8d1f9de497 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/config/DbConfig.java @@ -0,0 +1,61 @@ +package com.baeldung.config; + +import java.util.Properties; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +//@Configuration +@EnableJpaRepositories(basePackages = "com.baeldung.repositories") +// @PropertySource("persistence-h2.properties") +// @PropertySource("persistence-hsqldb.properties") +// @PropertySource("persistence-derby.properties") +public class DbConfig { + + @Autowired + private Environment env; + + @Bean + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(env.getProperty("driverClassName")); + dataSource.setUrl(env.getProperty("url")); + dataSource.setUsername(env.getProperty("user")); + dataSource.setPassword(env.getProperty("password")); + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "com.baeldung.models" }); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaProperties(additionalProperties()); + return em; + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + if (env.getProperty("hibernate.hbm2ddl.auto") != null) { + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + } + if (env.getProperty("hibernate.dialect") != null) { + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + } + if (env.getProperty("hibernate.show_sql") != null) { + hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + } + return hibernateProperties; + } + +} diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Address.java b/spring-data-rest/src/main/java/com/baeldung/models/Address.java index 98cf5f0869..82e3783f3e 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Address.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Address.java @@ -3,6 +3,7 @@ package com.baeldung.models; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; @@ -10,7 +11,7 @@ import javax.persistence.OneToOne; public class Address { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Author.java b/spring-data-rest/src/main/java/com/baeldung/models/Author.java index 7025fa4ad3..cdd04cbdcf 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Author.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Author.java @@ -6,6 +6,7 @@ import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; @@ -15,7 +16,7 @@ import javax.persistence.ManyToMany; public class Author { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Book.java b/spring-data-rest/src/main/java/com/baeldung/models/Book.java index 8f836a259a..06abfb8f4d 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Book.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Book.java @@ -5,6 +5,7 @@ import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToMany; @@ -14,7 +15,7 @@ import javax.persistence.ManyToOne; public class Book { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; @Column(nullable = false) diff --git a/spring-data-rest/src/main/java/com/baeldung/models/Library.java b/spring-data-rest/src/main/java/com/baeldung/models/Library.java index 61eead16ea..c27512d0e4 100644 --- a/spring-data-rest/src/main/java/com/baeldung/models/Library.java +++ b/spring-data-rest/src/main/java/com/baeldung/models/Library.java @@ -5,6 +5,7 @@ import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; @@ -16,7 +17,7 @@ import org.springframework.data.rest.core.annotation.RestResource; public class Library { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; @Column diff --git a/spring-data-rest/src/main/resources/persistence-derby.properties b/spring-data-rest/src/main/resources/persistence-derby.properties new file mode 100644 index 0000000000..9bcd91c6f9 --- /dev/null +++ b/spring-data-rest/src/main/resources/persistence-derby.properties @@ -0,0 +1,8 @@ +driverClassName=org.apache.derby.jdbc.EmbeddedDriver +url=jdbc:derby:memory:myD;create=true +username=sa +password= + +hibernate.dialect=org.hibernate.dialect.DerbyDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-data-rest/src/main/resources/persistence-h2.properties b/spring-data-rest/src/main/resources/persistence-h2.properties new file mode 100644 index 0000000000..d535f9dbe4 --- /dev/null +++ b/spring-data-rest/src/main/resources/persistence-h2.properties @@ -0,0 +1,8 @@ +driverClassName=org.h2.Driver +url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 +username=sa +password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-data-rest/src/main/resources/persistence-hsqldb.properties b/spring-data-rest/src/main/resources/persistence-hsqldb.properties new file mode 100644 index 0000000000..00464f1026 --- /dev/null +++ b/spring-data-rest/src/main/resources/persistence-hsqldb.properties @@ -0,0 +1,8 @@ +driverClassName=org.hsqldb.jdbc.JDBCDriver +url=jdbc:hsqldb:mem:myDb +username=sa +password= + +hibernate.dialect=org.hibernate.dialect.HSQLDialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-data-rest/src/main/resources/persistence-sqlite.properties b/spring-data-rest/src/main/resources/persistence-sqlite.properties new file mode 100644 index 0000000000..018c2cbaca --- /dev/null +++ b/spring-data-rest/src/main/resources/persistence-sqlite.properties @@ -0,0 +1,4 @@ +driverClassName=org.sqlite.JDBC +url=jdbc:sqlite:memory:myDb +username=sa +password=sa \ No newline at end of file From 1a05305b31f966f64e0f8e5fe1ea06ea26f62be2 Mon Sep 17 00:00:00 2001 From: lor6 Date: Mon, 3 Apr 2017 05:18:07 +0300 Subject: [PATCH 246/291] custom failureAnalyzer (#1559) --- .../FailureAnalyzerApplication.java | 15 +++++++++++ ...yBeanNotOfRequiredTypeFailureAnalyzer.java | 25 +++++++++++++++++++ .../com/baeldung/failureanalyzer/MyDAO.java | 5 ++++ .../baeldung/failureanalyzer/MySecondDAO.java | 8 ++++++ .../baeldung/failureanalyzer/MyService.java | 13 ++++++++++ .../main/resources/META-INF/spring.factories | 1 + 6 files changed, 67 insertions(+) create mode 100644 spring-boot/src/main/java/com/baeldung/failureanalyzer/FailureAnalyzerApplication.java create mode 100644 spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java create mode 100644 spring-boot/src/main/java/com/baeldung/failureanalyzer/MyDAO.java create mode 100644 spring-boot/src/main/java/com/baeldung/failureanalyzer/MySecondDAO.java create mode 100644 spring-boot/src/main/java/com/baeldung/failureanalyzer/MyService.java create mode 100644 spring-boot/src/main/resources/META-INF/spring.factories diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/FailureAnalyzerApplication.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/FailureAnalyzerApplication.java new file mode 100644 index 0000000000..3489732b6f --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/FailureAnalyzerApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.failureanalyzer; + +import javax.annotation.security.RolesAllowed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FailureAnalyzerApplication { + @RolesAllowed("*") + public static void main(String[] args) { + System.setProperty("security.basic.enabled", "false"); + SpringApplication.run(FailureAnalyzerApplication.class, args); + } +} diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java new file mode 100644 index 0000000000..2f83ad6b57 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java @@ -0,0 +1,25 @@ +package com.baeldung.failureanalyzer; + +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +public class MyBeanNotOfRequiredTypeFailureAnalyzer extends AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, BeanNotOfRequiredTypeException cause) { + return new FailureAnalysis(getDescription(cause), getAction(cause), cause); + } + + private String getDescription(BeanNotOfRequiredTypeException ex) { + return "The bean " + ex.getBeanName() // + + " could not be injected as " + ex.getRequiredType().getName() // + + " because it is of type " + ex.getActualType().getName(); + } + + private String getAction(BeanNotOfRequiredTypeException ex) { + return "Consider creating a bean with name "+ ex.getBeanName() // + + " of type " + ex.getRequiredType().getName(); + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyDAO.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyDAO.java new file mode 100644 index 0000000000..ddaeb28574 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyDAO.java @@ -0,0 +1,5 @@ +package com.baeldung.failureanalyzer; + +public class MyDAO { + +} diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MySecondDAO.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MySecondDAO.java new file mode 100644 index 0000000000..12dd73a05b --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MySecondDAO.java @@ -0,0 +1,8 @@ +package com.baeldung.failureanalyzer; + +import org.springframework.stereotype.Repository; + +@Repository("myDAO") +public class MySecondDAO { + +} diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyService.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyService.java new file mode 100644 index 0000000000..72334ca8fa --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyService.java @@ -0,0 +1,13 @@ +package com.baeldung.failureanalyzer; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Service; + +@Service +public class MyService { + + @Resource(name = "myDAO") + private MyDAO myDAO; + +} diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..e3d3aa4c8e --- /dev/null +++ b/spring-boot/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer \ No newline at end of file From 4d08f3db6d0e990d91fb146d141beb59975972df Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 3 Apr 2017 16:14:11 +0200 Subject: [PATCH 247/291] Refactor Analyzer examples (#1579) * Refactor Analyzer examples * Refactor Analyzer examples --- .../MyBeanNotOfRequiredTypeFailureAnalyzer.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java index 2f83ad6b57..2bbae8944a 100644 --- a/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java +++ b/spring-boot/src/main/java/com/baeldung/failureanalyzer/MyBeanNotOfRequiredTypeFailureAnalyzer.java @@ -4,7 +4,8 @@ import org.springframework.beans.factory.BeanNotOfRequiredTypeException; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; -public class MyBeanNotOfRequiredTypeFailureAnalyzer extends AbstractFailureAnalyzer { +public class MyBeanNotOfRequiredTypeFailureAnalyzer + extends AbstractFailureAnalyzer { @Override protected FailureAnalysis analyze(Throwable rootFailure, BeanNotOfRequiredTypeException cause) { @@ -12,14 +13,16 @@ public class MyBeanNotOfRequiredTypeFailureAnalyzer extends AbstractFailureAnaly } private String getDescription(BeanNotOfRequiredTypeException ex) { - return "The bean " + ex.getBeanName() // - + " could not be injected as " + ex.getRequiredType().getName() // - + " because it is of type " + ex.getActualType().getName(); + return String.format("The bean %s could not be injected as %s because it is of type %s", + ex.getBeanName(), + ex.getRequiredType().getName(), + ex.getActualType().getName()); } private String getAction(BeanNotOfRequiredTypeException ex) { - return "Consider creating a bean with name "+ ex.getBeanName() // - + " of type " + ex.getRequiredType().getName(); + return String.format("Consider creating a bean with name %s of type %s", + ex.getBeanName(), + ex.getRequiredType().getName()); } } From e7cc45644ebf45fb9725b78318a9e1faa7f934a0 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 3 Apr 2017 18:03:10 +0200 Subject: [PATCH 248/291] Optimize build (#1582) --- ...t.java => JsoupParserIntegrationTest.java} | 4 +- pom.xml | 1 + spring-data-gemfire/pom.xml | 6 +++ ...=> EmployeeRepositoryIntegrationTest.java} | 6 +-- spring-data-javaslang/pom.xml | 17 +++++-- ...gTests.java => SpringIntegrationTest.java} | 45 ++++++++++--------- 6 files changed, 50 insertions(+), 29 deletions(-) rename jsoup/src/test/java/com/baeldung/jsoup/{JsoupParserTest.java => JsoupParserIntegrationTest.java} (98%) rename spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/{EmployeeRepositoryTest.java => EmployeeRepositoryIntegrationTest.java} (96%) rename spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/{SpringTests.java => SpringIntegrationTest.java} (80%) diff --git a/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserTest.java b/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java similarity index 98% rename from jsoup/src/test/java/com/baeldung/jsoup/JsoupParserTest.java rename to jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java index ba6d7358bc..dadd57b0ed 100644 --- a/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserTest.java +++ b/jsoup/src/test/java/com/baeldung/jsoup/JsoupParserIntegrationTest.java @@ -14,9 +14,9 @@ import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -public class JsoupParserTest { +public class JsoupParserIntegrationTest { - Document doc; + private Document doc; @Before public void setUp() throws IOException { diff --git a/pom.xml b/pom.xml index c8d060ec04..a6b46a0e39 100644 --- a/pom.xml +++ b/pom.xml @@ -129,6 +129,7 @@ spring-data-couchbase-2 spring-data-dynamodb spring-data-elasticsearch + spring-data-javaslang spring-data-mongodb spring-data-neo4j spring-data-redis diff --git a/spring-data-gemfire/pom.xml b/spring-data-gemfire/pom.xml index f387b04651..eb450ebc81 100644 --- a/spring-data-gemfire/pom.xml +++ b/spring-data-gemfire/pom.xml @@ -75,6 +75,12 @@ org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + diff --git a/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java b/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryIntegrationTest.java similarity index 96% rename from spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java rename to spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryIntegrationTest.java index 8714ad2d81..26f7bc8a4e 100644 --- a/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryTest.java +++ b/spring-data-gemfire/src/test/java/com/baeldung/spring/data/gemfire/repository/EmployeeRepositoryIntegrationTest.java @@ -18,13 +18,13 @@ import static junit.framework.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=GemfireConfiguration.class, loader=AnnotationConfigContextLoader.class) -public class EmployeeRepositoryTest { +public class EmployeeRepositoryIntegrationTest { - @Autowired + @Autowired private EmployeeRepository employeeRepository; @Autowired - FunctionExecution execution; + private FunctionExecution execution; @Test public void whenEmployeeIsSaved_ThenAbleToRead(){ diff --git a/spring-data-javaslang/pom.xml b/spring-data-javaslang/pom.xml index c265e893cc..76fbce1e2e 100644 --- a/spring-data-javaslang/pom.xml +++ b/spring-data-javaslang/pom.xml @@ -1,8 +1,8 @@ 4.0.0 - spring-data-javaslangb - spring-data-javaslangb + spring-data-javaslang + spring-data-javaslang 0.0.1-SNAPSHOT UTF-8 @@ -65,7 +65,18 @@ ${project.build.testSourceDirectory} - + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + diff --git a/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java b/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringIntegrationTest.java similarity index 80% rename from spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java rename to spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringIntegrationTest.java index 59a6c120fa..7a23fa1ef2 100644 --- a/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringTests.java +++ b/spring-data-javaslang/src/test/java/com/baeldung/spring_data_tests/SpringIntegrationTest.java @@ -1,34 +1,33 @@ package com.baeldung.spring_data_tests; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.baeldung.spring_data_app.MainApp; import com.baeldung.spring_data.model.Book; import com.baeldung.spring_data.model.JavaBook; import com.baeldung.spring_data.repository.BookRepository; import com.baeldung.spring_data.repository.JavaBookRepository; - +import com.baeldung.spring_data_app.MainApp; +import javaslang.collection.List; +import javaslang.collection.Seq; +import javaslang.control.Option; +import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.test.context.junit4.SpringRunner; -import javaslang.collection.Seq; -import javaslang.collection.List; -import javaslang.control.Option; - import java.util.ArrayList; +import static org.assertj.core.api.Assertions.assertThat; + @RunWith(SpringRunner.class) @SpringBootTest(classes = MainApp.class,webEnvironment = WebEnvironment.NONE) -public class SpringTests { +public class SpringIntegrationTest { @Autowired - JavaBookRepository javaRepository; + private JavaBookRepository javaRepository; @Autowired - BookRepository repository; + private BookRepository repository; @Test public void should_return_seq(){ @@ -38,7 +37,8 @@ public class SpringTests { testBook.setAuthors(authors); Book book = repository.save(testBook); Option> books = repository.findByTitleContaining("Seq Test"); - assert(!books.isEmpty()); + + assertThat(books).isNotEmpty(); } @@ -50,8 +50,9 @@ public class SpringTests { testBook.setAuthors(authors); Book book = repository.save(testBook); Option retBook = repository.findById(1L); - assert(retBook.isDefined() && !retBook.isEmpty()); - assert(retBook.get() != null); + + assertThat(retBook.isDefined()).isTrue(); + assertThat(retBook).isNotEmpty(); } @Test @@ -64,9 +65,11 @@ public class SpringTests { testBook.setAuthors(authors); JavaBook book = javaRepository.save(testBook); java.util.List books = javaRepository.findByTitleContaining("Seq"); - assert(!books.isEmpty()); - assert(books.size() == 1); - assert(books.get(0).getTitle().equals("Javaslang in Spring Data Seq Return")); + assertThat(books) + .isNotEmpty() + .hasSize(1) + .extracting("title") + .contains("Javaslang in Spring Data Seq Return"); } @Test @@ -79,8 +82,8 @@ public class SpringTests { testBook.setAuthors(authors); JavaBook book = javaRepository.save(testBook); JavaBook retBook = javaRepository.findById(1L); - assert(retBook != null); - assert(retBook.getId() == 1L); - assert(retBook.getTitle().contains("Data")); + + assertThat(retBook.getId()).isEqualTo(1L); + assertThat(retBook.getTitle()).isEqualTo("Javaslang in Spring Data"); } } \ No newline at end of file From 2a76b9c65689b05054ae2d6d82dd77ef73496586 Mon Sep 17 00:00:00 2001 From: gitterjim-I Date: Mon, 3 Apr 2017 23:30:45 +0100 Subject: [PATCH 249/291] change test names, bael-667 (#1581) * article Bael-667 initial commit. * Switch to use logging framework for output. * Make code more concise. Refactor as suggested. * modify test method names --- .../list/flattennestedlist/FlattenNestedListTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java index b7939d09da..285b217156 100644 --- a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -17,7 +17,7 @@ public class FlattenNestedListTest { List> lol = asList(asList("one:one"), asList("two:one", "two:two", "two:three"), asList("three:one", "three:two", "three:three", "three:four")); @Test - public void givenString_flattenNestedList1() { + public void givenNestedList_thenFlattenNestedListImperative() { List ls = flattenListOfListsImperatively(lol); assertNotNull(ls); @@ -27,7 +27,7 @@ public class FlattenNestedListTest { } @Test - public void givenString_flattenNestedList2() { + public void givenNestedList_thenFlattenNestedListStream() { List ls = flattenListOfListsStream(lol); assertNotNull(ls); From 8da820b35a34ae0a5cc6cc54528032a4ee7e2ad7 Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Tue, 4 Apr 2017 00:35:35 +0200 Subject: [PATCH 250/291] BAEL-87 - @JsonComponent in Spring Boot (#1519) --- .../java/org/baeldung/jsoncomponent/User.java | 15 ++++++ .../jsoncomponent/UserCombinedSerializer.java | 46 +++++++++++++++++++ .../jsoncomponent/UserJsonDeserializer.java | 22 +++++++++ .../jsoncomponent/UserJsonSerializer.java | 29 ++++++++++++ .../UserJsonDeserializerTest.java | 27 +++++++++++ .../jsoncomponent/UserJsonSerializerTest.java | 27 +++++++++++ 6 files changed, 166 insertions(+) create mode 100644 spring-boot/src/main/java/org/baeldung/jsoncomponent/User.java create mode 100644 spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java create mode 100644 spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonDeserializer.java create mode 100644 spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonSerializer.java create mode 100644 spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java create mode 100644 spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java diff --git a/spring-boot/src/main/java/org/baeldung/jsoncomponent/User.java b/spring-boot/src/main/java/org/baeldung/jsoncomponent/User.java new file mode 100644 index 0000000000..8961874526 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/jsoncomponent/User.java @@ -0,0 +1,15 @@ +package org.baeldung.jsoncomponent; + +import javafx.scene.paint.Color; + +public class User { + private final Color favoriteColor; + + public User(Color favoriteColor) { + this.favoriteColor = favoriteColor; + } + + public Color getFavoriteColor() { + return favoriteColor; + } +} diff --git a/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java new file mode 100644 index 0000000000..302b0dce61 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java @@ -0,0 +1,46 @@ +package org.baeldung.jsoncomponent; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.node.TextNode; +import javafx.scene.paint.Color; +import org.springframework.boot.jackson.JsonComponent; + +import java.io.IOException; + +@JsonComponent +public class UserCombinedSerializer { + public static class UserJsonSerializer extends JsonSerializer { + + @Override + public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField("favoriteColor", + getColorAsWebColor(user.getFavoriteColor())); + jsonGenerator.writeEndObject(); + } + + private static String getColorAsWebColor(Color color) { + int r = (int) Math.round(color.getRed() * 255.0); + int g = (int) Math.round(color.getGreen() * 255.0); + int b = (int) Math.round(color.getBlue() * 255.0); + return String.format("#%02x%02x%02x", r, g, b); + } + } + + @JsonComponent + public static class UserJsonDeserializer extends JsonDeserializer { + @Override + public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser); + TextNode favoriteColor = (TextNode) treeNode.get("favoriteColor"); + return new User(Color.web(favoriteColor.asText())); + } + } +} diff --git a/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonDeserializer.java b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonDeserializer.java new file mode 100644 index 0000000000..d18de7e3f1 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonDeserializer.java @@ -0,0 +1,22 @@ +package org.baeldung.jsoncomponent; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.node.TextNode; +import javafx.scene.paint.Color; +import org.springframework.boot.jackson.JsonComponent; + +import java.io.IOException; + +@JsonComponent +public class UserJsonDeserializer extends JsonDeserializer { + @Override + public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser); + TextNode favoriteColor = (TextNode) treeNode.get("favoriteColor"); + return new User(Color.web(favoriteColor.asText())); + } +} diff --git a/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonSerializer.java b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonSerializer.java new file mode 100644 index 0000000000..d90f662a4b --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserJsonSerializer.java @@ -0,0 +1,29 @@ +package org.baeldung.jsoncomponent; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import javafx.scene.paint.Color; +import org.springframework.boot.jackson.JsonComponent; + +import java.io.IOException; + +@JsonComponent +public class UserJsonSerializer extends JsonSerializer { + + @Override + public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField("favoriteColor", + getColorAsWebColor(user.getFavoriteColor())); + jsonGenerator.writeEndObject(); + } + + private static String getColorAsWebColor(Color color) { + int r = (int) Math.round(color.getRed() * 255.0); + int g = (int) Math.round(color.getGreen() * 255.0); + int b = (int) Math.round(color.getBlue() * 255.0); + return String.format("#%02x%02x%02x", r, g, b); + } +} diff --git a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java new file mode 100644 index 0000000000..51c1c72ea3 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java @@ -0,0 +1,27 @@ +package org.baeldung.jsoncomponent; + +import com.fasterxml.jackson.databind.ObjectMapper; +import javafx.scene.paint.Color; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +@JsonTest +@RunWith(SpringRunner.class) +public class UserJsonDeserializerTest { + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void testDeserialize() throws IOException { + User user = objectMapper.readValue("{\"favoriteColor\":\"#f0f8ff\"}", User.class); + assertEquals(Color.ALICEBLUE, user.getFavoriteColor()); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java new file mode 100644 index 0000000000..c85af4a17f --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java @@ -0,0 +1,27 @@ +package org.baeldung.jsoncomponent; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import javafx.scene.paint.Color; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; + +@JsonTest +@RunWith(SpringRunner.class) +public class UserJsonSerializerTest { + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void testSerialization() throws JsonProcessingException { + String json = objectMapper.writeValueAsString(new User(Color.ALICEBLUE)); + assertEquals("{\"favoriteColor\":\"#f0f8ff\"}", json); + } +} \ No newline at end of file From 975ee3bc8554847064aa1145a4331b4a3653f309 Mon Sep 17 00:00:00 2001 From: sp619r Date: Mon, 3 Apr 2017 21:02:58 -0700 Subject: [PATCH 251/291] BAEL-679 second draft --- .../java9/reactive/BaeldungBatchSubscriberImpl.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java index 4c65cb35b6..46eee4883a 100644 --- a/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java +++ b/core-java-9/src/main/java/com/baeldung/java9/reactive/BaeldungBatchSubscriberImpl.java @@ -43,11 +43,9 @@ public class BaeldungBatchSubscriberImpl implements Subscriber { // if buffer is full, process the items. if (buffer.size() >= BUFFER_SIZE) { processBuffer(); - subscription.request(BUFFER_SIZE); - } else if(buffer.size() == 0) { - // If buffer empty, request more items. - subscription.request(BUFFER_SIZE); } + //request more items. + subscription.request(1); } private void processBuffer() { From a4f4301196de133395001482597c4d6267ff7fbf Mon Sep 17 00:00:00 2001 From: Yasin Date: Tue, 4 Apr 2017 15:58:51 +0530 Subject: [PATCH 252/291] BAEL-729 Adding custom info to actuator's /info endpoint (#1584) * yasin.bhojawala@gmail.com Evaluation article on Different Types of Bean Injection in Spring * Revert "yasin.bhojawala@gmail.com" This reverts commit 963cc51a7a15b75b550108fe4e198cd65a274032. * Fixing compilation error and removing unused import * Introduction to Java9 StackWalking API - yasin.bhojawala@gmail.com Code examples for the article "Introduction to Java9 StackWalking API" * BAEL-608 Introduction to Java9 StackWalking API * BAEL-608 Introduction to Java9 StackWalking API changing the test names to BDD style * BAEL-608 Introduction to Java9 StackWalking API correcting the typo * BAEL-608 Introduction to Java9 StackWalking API improving method names * BAEL-608 Introduction to Java9 StackWalking API test method names improvements * BAEL-718 Quick intro to javatuples * merging pom from master * BAEL-722 Intro to JSONassert * BAEL-722 Intro to JSONassert Updated to 1.5.0 * BAEL-745 Quick Math.pow example * BAEL-729 Adding custom info to actuator's /info endpoint --- .../java/org/baeldung/boot/model/User.java | 41 +++++++++++++++++++ .../boot/repository/UserRepository.java | 10 +++++ .../info/TotalUsersInfoContributor.java | 26 ++++++++++++ .../src/main/resources/application.properties | 5 ++- spring-boot/src/main/resources/data.sql | 5 +++ spring-boot/src/main/resources/schema.sql | 6 +++ 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/main/java/org/baeldung/boot/model/User.java create mode 100644 spring-boot/src/main/java/org/baeldung/boot/repository/UserRepository.java create mode 100644 spring-boot/src/main/java/org/baeldung/endpoints/info/TotalUsersInfoContributor.java create mode 100644 spring-boot/src/main/resources/data.sql create mode 100644 spring-boot/src/main/resources/schema.sql diff --git a/spring-boot/src/main/java/org/baeldung/boot/model/User.java b/spring-boot/src/main/java/org/baeldung/boot/model/User.java new file mode 100644 index 0000000000..f60ac86fe4 --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/model/User.java @@ -0,0 +1,41 @@ +package org.baeldung.boot.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue + private Integer id; + private String name; + private Integer status; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/spring-boot/src/main/java/org/baeldung/boot/repository/UserRepository.java b/spring-boot/src/main/java/org/baeldung/boot/repository/UserRepository.java new file mode 100644 index 0000000000..3a419a65bd --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/boot/repository/UserRepository.java @@ -0,0 +1,10 @@ +package org.baeldung.boot.repository; + +import org.baeldung.boot.model.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository("userRepository") +public interface UserRepository extends JpaRepository { + public int countByStatus(int status); +} diff --git a/spring-boot/src/main/java/org/baeldung/endpoints/info/TotalUsersInfoContributor.java b/spring-boot/src/main/java/org/baeldung/endpoints/info/TotalUsersInfoContributor.java new file mode 100644 index 0000000000..790584644f --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/endpoints/info/TotalUsersInfoContributor.java @@ -0,0 +1,26 @@ +package org.baeldung.endpoints.info; + +import java.util.HashMap; +import java.util.Map; + +import org.baeldung.boot.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.stereotype.Component; + +@Component +public class TotalUsersInfoContributor implements InfoContributor { + + @Autowired + UserRepository userRepository; + + @Override + public void contribute(Info.Builder builder) { + Map userDetails = new HashMap<>(); + userDetails.put("active", userRepository.countByStatus(1)); + userDetails.put("inactive", userRepository.countByStatus(0)); + + builder.withDetail("users", userDetails); + } +} diff --git a/spring-boot/src/main/resources/application.properties b/spring-boot/src/main/resources/application.properties index 1ffc95849d..84315a2477 100644 --- a/spring-boot/src/main/resources/application.properties +++ b/spring-boot/src/main/resources/application.properties @@ -2,7 +2,9 @@ server.port=8080 server.contextPath=/springbootapp management.port=8081 management.address=127.0.0.1 - +#debug=true +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto = update endpoints.shutdown.enabled=true endpoints.jmx.domain=Spring Sample Application @@ -22,6 +24,7 @@ http.mappers.jsonPrettyPrint=true info.app.name=Spring Sample Application info.app.description=This is my first spring boot application G1 info.app.version=1.0.0 +info.java-vendor = ${java.specification.vendor} ## Spring Security Configurations security.user.name=admin1 diff --git a/spring-boot/src/main/resources/data.sql b/spring-boot/src/main/resources/data.sql new file mode 100644 index 0000000000..c44034c739 --- /dev/null +++ b/spring-boot/src/main/resources/data.sql @@ -0,0 +1,5 @@ +insert into users values (1, 'Alex', 1); +insert into users values (2, 'Bob', 1); +insert into users values (3, 'John', 0); +insert into users values (4, 'Harry', 0); +insert into users values (5, 'Smith', 1); \ No newline at end of file diff --git a/spring-boot/src/main/resources/schema.sql b/spring-boot/src/main/resources/schema.sql new file mode 100644 index 0000000000..27859c1652 --- /dev/null +++ b/spring-boot/src/main/resources/schema.sql @@ -0,0 +1,6 @@ +create table USERS( + ID int not null AUTO_INCREMENT, + NAME varchar(100) not null, + STATUS int, + PRIMARY KEY ( ID ) +); \ No newline at end of file From 50ff1d18c481668f4b1edd2d4af4369c9564e5ba Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Tue, 4 Apr 2017 16:02:55 +0530 Subject: [PATCH 253/291] quick-guide-to-the-java-stringtokenizer (#1587) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * changing banner format in plain text * Delete banner.txt~ * Delete b.txt~ * CORS in JAX-RS * ratpack with google guice * adding factory instance example * quick-guide-to-the-java-stringtokenizer * Update Application.java * Delete MovieCrudService.java~ --- .../baeldung/stringtokenizer/Application.java | 21 +++++++++++++ .../stringtokenizer/ApplicationTest.java | 30 +++++++++++++++++++ .../main/java/com/baeldung/Application.java | 1 + .../java/com/baeldung/filter/CORSFilter.java | 18 +++++++++++ 4 files changed, 70 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/stringtokenizer/Application.java create mode 100644 core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java create mode 100644 resteasy/src/main/java/com/baeldung/filter/CORSFilter.java diff --git a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java new file mode 100644 index 0000000000..caa7ef06da --- /dev/null +++ b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java @@ -0,0 +1,21 @@ +package com.baeldung.stringtokenizer; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +public class Application { + + public List getTokens(String str) { + List tokens = new ArrayList(); +// StringTokenizer tokenizer = new StringTokenizer( str ); + StringTokenizer tokenizer = new StringTokenizer( str , "," ); +// StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); + while (tokenizer.hasMoreElements()) { + tokens.add( tokenizer.nextToken() ); +// tokens.add( tokenizer.nextToken( "," ) ); + } + return tokens; + } + +} diff --git a/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java b/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java new file mode 100644 index 0000000000..5e3df5b303 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java @@ -0,0 +1,30 @@ +package com.baeldung.stringtokenizer; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ApplicationTest { + + Application application = new Application(); + List expectedTokens = new ArrayList(); + + @Before + public void init() { + expectedTokens.add( "Welcome" ); + expectedTokens.add( "to" ); + expectedTokens.add( "baeldung.com" ); + } + + @Test + public void givenString_thenGetListOfString() { + String str = "Welcome,to,baeldung.com"; + List actualTokens = application.getTokens(str); + assertEquals(expectedTokens, actualTokens); + } + +} diff --git a/ratpack/src/main/java/com/baeldung/Application.java b/ratpack/src/main/java/com/baeldung/Application.java index 94709e88e9..7f46b241ea 100644 --- a/ratpack/src/main/java/com/baeldung/Application.java +++ b/ratpack/src/main/java/com/baeldung/Application.java @@ -46,3 +46,4 @@ public class Application { } } + diff --git a/resteasy/src/main/java/com/baeldung/filter/CORSFilter.java b/resteasy/src/main/java/com/baeldung/filter/CORSFilter.java new file mode 100644 index 0000000000..16562d4359 --- /dev/null +++ b/resteasy/src/main/java/com/baeldung/filter/CORSFilter.java @@ -0,0 +1,18 @@ +package com.baeldung.filter; + +import java.io.IOException; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; + +public class CORSFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + responseContext.getHeaders().add("Access-Control-Allow-Origin", "*"); + + } + +} From eb26f83cd18ce3c4ab05dfecc4b0df89f2b8e800 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Tue, 4 Apr 2017 22:48:41 +0200 Subject: [PATCH 254/291] Bael 770 jetty (#1548) * BAEL-770 add jetty simple test case * BAEL-770 jetty async and blocking servlets * BAEL-766 reorder --- libraries/pom.xml | 25 +++++++- .../java/com/baeldung/jetty/AsyncServlet.java | 42 ++++++++++++++ .../com/baeldung/jetty/BlockingServlet.java | 17 ++++++ .../java/com/baeldung/jetty/JettyServer.java | 32 ++++++++++ .../java/com/baeldung/jetty/JettyTest.java | 58 +++++++++++++++++++ 5 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 libraries/src/main/java/com/baeldung/jetty/AsyncServlet.java create mode 100644 libraries/src/main/java/com/baeldung/jetty/BlockingServlet.java create mode 100644 libraries/src/main/java/com/baeldung/jetty/JettyServer.java create mode 100644 libraries/src/test/java/com/baeldung/jetty/JettyTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 11295230b4..0f33c42dc4 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> parent-modules com.baeldung @@ -72,6 +72,26 @@ javers-core ${javers.version} + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-io + commons-io + ${commons.io.version} + @@ -84,6 +104,9 @@ 3.6.2 1.5.0 3.1.0 + 9.4.2.v20170220 + 4.5.3 + 2.5 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/jetty/AsyncServlet.java b/libraries/src/main/java/com/baeldung/jetty/AsyncServlet.java new file mode 100644 index 0000000000..d1bddd097f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/jetty/AsyncServlet.java @@ -0,0 +1,42 @@ +package com.baeldung.jetty; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class AsyncServlet extends HttpServlet { + private static final String HEAVY_RESOURCE = "This is some heavy resource that will be served in an async way"; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + ByteBuffer content = ByteBuffer.wrap(HEAVY_RESOURCE.getBytes(StandardCharsets.UTF_8)); + + AsyncContext async = request.startAsync(); + ServletOutputStream out = response.getOutputStream(); + out.setWriteListener(new WriteListener() { + @Override + public void onWritePossible() throws IOException { + while (out.isReady()) { + if (!content.hasRemaining()) { + response.setStatus(200); + async.complete(); + return; + } + out.write(content.get()); + } + } + + @Override + public void onError(Throwable t) { + getServletContext().log("Async Error", t); + async.complete(); + } + }); + } +} \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/jetty/BlockingServlet.java b/libraries/src/main/java/com/baeldung/jetty/BlockingServlet.java new file mode 100644 index 0000000000..f1de71beeb --- /dev/null +++ b/libraries/src/main/java/com/baeldung/jetty/BlockingServlet.java @@ -0,0 +1,17 @@ +package com.baeldung.jetty; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class BlockingServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().println("{ \"status\": \"ok\"}"); + } +} + diff --git a/libraries/src/main/java/com/baeldung/jetty/JettyServer.java b/libraries/src/main/java/com/baeldung/jetty/JettyServer.java new file mode 100644 index 0000000000..1365de866a --- /dev/null +++ b/libraries/src/main/java/com/baeldung/jetty/JettyServer.java @@ -0,0 +1,32 @@ +package com.baeldung.jetty; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletHandler; + +public class JettyServer { + + private Server server; + + public void start() throws Exception { + + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(8090); + server.setConnectors(new Connector[]{connector}); + + ServletHandler servletHandler = new ServletHandler(); + server.setHandler(servletHandler); + + servletHandler.addServletWithMapping(BlockingServlet.class, "/status"); + servletHandler.addServletWithMapping(AsyncServlet.class, "/heavy/async"); + + server.start(); + + } + + public void stop() throws Exception { + server.stop(); + } +} diff --git a/libraries/src/test/java/com/baeldung/jetty/JettyTest.java b/libraries/src/test/java/com/baeldung/jetty/JettyTest.java new file mode 100644 index 0000000000..caf70f9af3 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/jetty/JettyTest.java @@ -0,0 +1,58 @@ +package com.baeldung.jetty; + + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class JettyTest { + private JettyServer jettyServer; + + @Before + public void setup() throws Exception { + jettyServer = new JettyServer(); + jettyServer.start(); + } + + @After + public void cleanup() throws Exception { + Thread.sleep(2000); + jettyServer.stop(); + } + + @Test + public void givenServer_whenSendRequestToBlockingServlet_thenReturnStatusOK() throws Exception { + //given + String url = "http://localhost:8090/status"; + HttpClient client = HttpClientBuilder.create().build(); + HttpGet request = new HttpGet(url); + HttpResponse response = client.execute(request); + + //then + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + + } + + @Test + public void givenServer_whenSendRequestToNonBlockingServlet_thenReturnStatusOK() throws Exception { + //when + String url = "http://localhost:8090/heavy/async"; + HttpClient client = HttpClientBuilder.create().build(); + HttpGet request = new HttpGet(url); + HttpResponse response = client.execute(request); + + //then + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); + String responseContent = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + assertThat(responseContent).isEqualTo("This is some heavy resource that will be served in an async way"); + } +} From cb9c16a5330bc52bc0dc45f984d61e02ec736bb7 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Wed, 5 Apr 2017 09:20:39 +0200 Subject: [PATCH 255/291] Optimize build (#1592) * Optimize build * Optimize build --- apache-poi/temp.xlsx | Bin 3492 -> 3492 bytes mesos-marathon/pom.xml | 10 ++++++++ .../DemoApplication.java | 4 +--- .../HelloController.java | 3 +-- .../DemoApplicationIntegrationTest.java} | 5 ++-- pom.xml | 4 ++-- spring-amqp-simple/pom.xml | 10 ++++++++ spring-aop/pom.xml | 16 +++++++++++-- ...a => CustomAnnotationIntegrationTest.java} | 2 +- ... UserJsonDeserializerIntegrationTest.java} | 2 +- ...=> UserJsonSerializerIntegrationTest.java} | 2 +- ...t.java => SaveMethodsIntegrationTest.java} | 2 +- .../criteria/HibernateCriteriaTestRunner.java | 15 ------------ .../criteria/HibernateCriteriaTestSuite.java | 11 --------- ...st.java => SaveMethodIntegrationTest.java} | 22 +++++------------- ...kMvc.java => EmployeeIntegrationTest.java} | 2 +- ...equestMapingShortcutsIntegrationTest.java} | 2 +- spring-security-rest/pom.xml | 2 +- ...va => AsyncControllerIntegrationTest.java} | 6 ++--- ... ForkJoinStateMachineIntegrationTest.java} | 2 +- ...rarchicalStateMachineIntegrationTest.java} | 2 +- ... JunctionStateMachineIntegrationTest.java} | 2 +- ...a => StateEnumMachineIntegrationTest.java} | 2 +- 23 files changed, 60 insertions(+), 68 deletions(-) rename mesos-marathon/src/main/java/com/{mogronalol => baeldung}/DemoApplication.java (81%) rename mesos-marathon/src/main/java/com/{mogronalol => baeldung}/HelloController.java (82%) rename mesos-marathon/src/test/java/com/{mogronalol/DemoApplicationTests.java => baeldung/DemoApplicationIntegrationTest.java} (88%) rename spring-aop/src/test/java/org/baeldung/{CustomAnnotationTest.java => CustomAnnotationIntegrationTest.java} (91%) rename spring-boot/src/test/java/org/baeldung/jsoncomponent/{UserJsonDeserializerTest.java => UserJsonDeserializerIntegrationTest.java} (93%) rename spring-boot/src/test/java/org/baeldung/jsoncomponent/{UserJsonSerializerTest.java => UserJsonSerializerIntegrationTest.java} (94%) rename spring-hibernate4/src/test/java/com/baeldung/persistence/save/{SaveMethodsTest.java => SaveMethodsIntegrationTest.java} (99%) delete mode 100644 spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java delete mode 100644 spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestSuite.java rename spring-hibernate5/src/test/java/com/baeldung/persistence/save/{SaveMethodsTest.java => SaveMethodIntegrationTest.java} (94%) rename spring-mvc-java/src/test/java/com/baeldung/web/controller/{EmployeeTestWithoutMockMvc.java => EmployeeIntegrationTest.java} (97%) rename spring-mvc-java/src/test/java/com/baeldung/web/controller/{RequestMapingShortcutsUnitTest.java => RequestMapingShortcutsIntegrationTest.java} (98%) rename spring-security-rest/src/test/java/org/baeldung/web/{AsyncControllerTest.java => AsyncControllerIntegrationTest.java} (97%) rename spring-state-machine/src/test/java/com/baeldung/spring/statemachine/{ForkJoinStateMachineTest.java => ForkJoinStateMachineIntegrationTest.java} (97%) rename spring-state-machine/src/test/java/com/baeldung/spring/statemachine/{HierarchicalStateMachineTest.java => HierarchicalStateMachineIntegrationTest.java} (96%) rename spring-state-machine/src/test/java/com/baeldung/spring/statemachine/{JunctionStateMachineTest.java => JunctionStateMachineIntegrationTest.java} (96%) rename spring-state-machine/src/test/java/com/baeldung/spring/statemachine/{StateEnumMachineTest.java => StateEnumMachineIntegrationTest.java} (97%) diff --git a/apache-poi/temp.xlsx b/apache-poi/temp.xlsx index 12a9b2656c24c1605df94f1a00c1f792a580f154..431a8a662c2cacd3363a1593bc24df699ae34c98 100644 GIT binary patch delta 460 zcmZ1?y+oQfz?+#xgn@&DgJFej>qcG~MrI(rS%_~9^sHc(~om1zrDE9unE$c+DoStb}Jmcr7yMeqftu5|L z$12Vep3)@d_HEbN3(lL*p9_4&e0>tXn{(?H$K6(%t*M7BEG&`_w#wB=+1@fv)V|W1 zAbBjVWWkQ}$_pQVIBId!StqtzSA2c_9@afdDczzhdX*0O_xS6*rv3cj@rm zuj(v%Z2O|O E02C#=wg3PC delta 460 zcmZ1?y+oQfz?+#xgn@&DgW*79#YSEkMrI(rS%DmQx=gyeR8`p2OU13g<4GuJ#h$ggec8*Dd~TU>w9kC)$`)mhp}fBCbUK_uR8*UW+g z%qL8wB7STzoc#V|a%JV!cLBiyRnsOKX`AWVCYBuLs9g79{okWMLM5)p9Py~~_+Eb9 zSbfK~$z1g>5}FO{q7cRm4rusp z=Uf5_-#BhFaQIH=wgb~QxUD&W;q3)7eX=x + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + diff --git a/mesos-marathon/src/main/java/com/mogronalol/DemoApplication.java b/mesos-marathon/src/main/java/com/baeldung/DemoApplication.java similarity index 81% rename from mesos-marathon/src/main/java/com/mogronalol/DemoApplication.java rename to mesos-marathon/src/main/java/com/baeldung/DemoApplication.java index f757178026..b2c5302277 100644 --- a/mesos-marathon/src/main/java/com/mogronalol/DemoApplication.java +++ b/mesos-marathon/src/main/java/com/baeldung/DemoApplication.java @@ -1,10 +1,8 @@ -package com.mogronalol; +package com.baeldung; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import javax.annotation.PostConstruct; - @SpringBootApplication public class DemoApplication { diff --git a/mesos-marathon/src/main/java/com/mogronalol/HelloController.java b/mesos-marathon/src/main/java/com/baeldung/HelloController.java similarity index 82% rename from mesos-marathon/src/main/java/com/mogronalol/HelloController.java rename to mesos-marathon/src/main/java/com/baeldung/HelloController.java index 2059280ba0..83eca1f501 100644 --- a/mesos-marathon/src/main/java/com/mogronalol/HelloController.java +++ b/mesos-marathon/src/main/java/com/baeldung/HelloController.java @@ -1,6 +1,5 @@ -package com.mogronalol; +package com.baeldung; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; diff --git a/mesos-marathon/src/test/java/com/mogronalol/DemoApplicationTests.java b/mesos-marathon/src/test/java/com/baeldung/DemoApplicationIntegrationTest.java similarity index 88% rename from mesos-marathon/src/test/java/com/mogronalol/DemoApplicationTests.java rename to mesos-marathon/src/test/java/com/baeldung/DemoApplicationIntegrationTest.java index 5e88f9a70f..85331516f9 100644 --- a/mesos-marathon/src/test/java/com/mogronalol/DemoApplicationTests.java +++ b/mesos-marathon/src/test/java/com/baeldung/DemoApplicationIntegrationTest.java @@ -1,11 +1,10 @@ -package com.mogronalol; +package com.baeldung; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.client.RestTemplate; @@ -13,7 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = {DemoApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class DemoApplicationTests { +public class DemoApplicationIntegrationTest { private RestTemplate restTemplate; diff --git a/pom.xml b/pom.xml index a6b46a0e39..a582ff3e70 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ deltaspike dozer - ejb + feign flyway @@ -66,7 +66,7 @@ javax-servlets javaxval jaxb - jee7 + jjwt jooq diff --git a/spring-amqp-simple/pom.xml b/spring-amqp-simple/pom.xml index 38738d875f..7ff26376e4 100644 --- a/spring-amqp-simple/pom.xml +++ b/spring-amqp-simple/pom.xml @@ -41,6 +41,16 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + \ No newline at end of file diff --git a/spring-aop/pom.xml b/spring-aop/pom.xml index bd86839742..90e892b311 100644 --- a/spring-aop/pom.xml +++ b/spring-aop/pom.xml @@ -2,10 +2,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - spring-custom-aop + spring-aop 0.0.1-SNAPSHOT war - spring-custom-aop + spring-aop org.springframework.boot @@ -42,6 +42,18 @@ 1.8 + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*IntegrationTest.java + **/*LiveTest.java + + + + diff --git a/spring-aop/src/test/java/org/baeldung/CustomAnnotationTest.java b/spring-aop/src/test/java/org/baeldung/CustomAnnotationIntegrationTest.java similarity index 91% rename from spring-aop/src/test/java/org/baeldung/CustomAnnotationTest.java rename to spring-aop/src/test/java/org/baeldung/CustomAnnotationIntegrationTest.java index d4712cc063..b109e3a39e 100644 --- a/spring-aop/src/test/java/org/baeldung/CustomAnnotationTest.java +++ b/spring-aop/src/test/java/org/baeldung/CustomAnnotationIntegrationTest.java @@ -8,7 +8,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest -public class CustomAnnotationTest { +public class CustomAnnotationIntegrationTest { @Autowired private Service service; diff --git a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerIntegrationTest.java similarity index 93% rename from spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java rename to spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerIntegrationTest.java index 51c1c72ea3..4f5af3d0e7 100644 --- a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerTest.java +++ b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonDeserializerIntegrationTest.java @@ -14,7 +14,7 @@ import static org.junit.Assert.assertEquals; @JsonTest @RunWith(SpringRunner.class) -public class UserJsonDeserializerTest { +public class UserJsonDeserializerIntegrationTest { @Autowired private ObjectMapper objectMapper; diff --git a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerIntegrationTest.java similarity index 94% rename from spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java rename to spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerIntegrationTest.java index c85af4a17f..c1b4c8912c 100644 --- a/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerTest.java +++ b/spring-boot/src/test/java/org/baeldung/jsoncomponent/UserJsonSerializerIntegrationTest.java @@ -14,7 +14,7 @@ import static org.junit.Assert.assertEquals; @JsonTest @RunWith(SpringRunner.class) -public class UserJsonSerializerTest { +public class UserJsonSerializerIntegrationTest { @Autowired private ObjectMapper objectMapper; diff --git a/spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java b/spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsIntegrationTest.java similarity index 99% rename from spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java rename to spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsIntegrationTest.java index 2e729c5680..ef83af3a0d 100644 --- a/spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java +++ b/spring-hibernate4/src/test/java/com/baeldung/persistence/save/SaveMethodsIntegrationTest.java @@ -16,7 +16,7 @@ import static org.junit.Assert.*; * Testing specific implementation details for different methods: * persist, save, merge, update, saveOrUpdate. */ -public class SaveMethodsTest { +public class SaveMethodsIntegrationTest { private static SessionFactory sessionFactory; diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java deleted file mode 100644 index 3228f917fd..0000000000 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestRunner.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.hibernate.criteria; - -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; -import org.junit.runner.notification.Failure; - -public class HibernateCriteriaTestRunner { - - public static void main(final String[] args) { - Result result = JUnitCore.runClasses(HibernateCriteriaTestSuite.class); - for (Failure failure : result.getFailures()) { - // - } - } -} diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestSuite.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestSuite.java deleted file mode 100644 index dc1040734f..0000000000 --- a/spring-hibernate5/src/test/java/com/baeldung/hibernate/criteria/HibernateCriteriaTestSuite.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.baeldung.hibernate.criteria; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ HibernateCriteriaIntegrationTest.class }) - -public class HibernateCriteriaTestSuite { - -} diff --git a/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java b/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodIntegrationTest.java similarity index 94% rename from spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java rename to spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodIntegrationTest.java index d3e90a568a..910cdc597f 100644 --- a/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodsTest.java +++ b/spring-hibernate5/src/test/java/com/baeldung/persistence/save/SaveMethodIntegrationTest.java @@ -1,14 +1,6 @@ package com.baeldung.persistence.save; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; - -import javax.persistence.PersistenceException; - +import com.baeldung.persistence.model.Person; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; @@ -17,19 +9,17 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.dialect.HSQLDialect; import org.hibernate.service.ServiceRegistry; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; -import com.baeldung.persistence.model.Person; +import javax.persistence.PersistenceException; + +import static org.junit.Assert.*; /** * Testing specific implementation details for different methods: persist, save, * merge, update, saveOrUpdate. */ -public class SaveMethodsTest { +public class SaveMethodIntegrationTest { private static SessionFactory sessionFactory; diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeTestWithoutMockMvc.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeIntegrationTest.java similarity index 97% rename from spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeTestWithoutMockMvc.java rename to spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeIntegrationTest.java index 19806e0559..0c2aa3de1b 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeTestWithoutMockMvc.java +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/EmployeeIntegrationTest.java @@ -15,7 +15,7 @@ import com.baeldung.spring.web.config.WebConfig; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) -public class EmployeeTestWithoutMockMvc { +public class EmployeeIntegrationTest { @Autowired private EmployeeController employeeController; diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsUnitTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsIntegrationTest.java similarity index 98% rename from spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsUnitTest.java rename to spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsIntegrationTest.java index d02a7140b5..fb21905027 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsUnitTest.java +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/RequestMapingShortcutsIntegrationTest.java @@ -21,7 +21,7 @@ import com.baeldung.spring.web.config.WebConfig; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) -public class RequestMapingShortcutsUnitTest { +public class RequestMapingShortcutsIntegrationTest { @Autowired private WebApplicationContext ctx; diff --git a/spring-security-rest/pom.xml b/spring-security-rest/pom.xml index 320e84fa7a..996161c721 100644 --- a/spring-security-rest/pom.xml +++ b/spring-security-rest/pom.xml @@ -259,10 +259,10 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} **/*LiveTest.java + **/*IntegrationTest.java diff --git a/spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerTest.java b/spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerIntegrationTest.java similarity index 97% rename from spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerTest.java rename to spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerIntegrationTest.java index 9cd92880a7..a09c225a4a 100644 --- a/spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerTest.java +++ b/spring-security-rest/src/test/java/org/baeldung/web/AsyncControllerIntegrationTest.java @@ -1,7 +1,5 @@ package org.baeldung.web; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - import org.baeldung.spring.ClientWebConfig; import org.baeldung.spring.SecurityJavaConfig; import org.baeldung.spring.WebConfig; @@ -20,10 +18,12 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = { ClientWebConfig.class, SecurityJavaConfig.class, WebConfig.class }) -public class AsyncControllerTest { +public class AsyncControllerIntegrationTest { @Autowired WebApplicationContext wac; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java similarity index 97% rename from spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java rename to spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java index a9aca82a6e..b34d5c47c6 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/ForkJoinStateMachineIntegrationTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = ForkJoinStateMachineConfiguration.class) -public class ForkJoinStateMachineTest { +public class ForkJoinStateMachineIntegrationTest { @Autowired private StateMachine stateMachine; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java similarity index 96% rename from spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java rename to spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java index a2fa4f9160..3d7c0be828 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/HierarchicalStateMachineIntegrationTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = HierarchicalStateMachineConfiguration.class) -public class HierarchicalStateMachineTest { +public class HierarchicalStateMachineIntegrationTest { @Autowired private StateMachine stateMachine; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java similarity index 96% rename from spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java rename to spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java index 2b5130ab45..93de23fad3 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/JunctionStateMachineIntegrationTest.java @@ -17,7 +17,7 @@ import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = JunctionStateMachineConfiguration.class) -public class JunctionStateMachineTest { +public class JunctionStateMachineIntegrationTest { @Autowired private StateMachine stateMachine; diff --git a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java similarity index 97% rename from spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java rename to spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java index 19f24ede2d..9074ece001 100644 --- a/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineTest.java +++ b/spring-state-machine/src/test/java/com/baeldung/spring/statemachine/StateEnumMachineIntegrationTest.java @@ -21,7 +21,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SimpleEnumStateMachineConfiguration.class) -public class StateEnumMachineTest { +public class StateEnumMachineIntegrationTest { @Autowired private StateMachine stateMachine; From bbcafe2e329d1d2b12183425ac585def18eedb1d Mon Sep 17 00:00:00 2001 From: Wim Deblauwe Date: Wed, 5 Apr 2017 11:01:21 +0200 Subject: [PATCH 256/291] Feature/bael 87 (#1590) * BAEL-87 - @JsonComponent in Spring Boot * BAEL-87 - @JsonComponent in Spring Boot * BAEL-87 - @JsonComponent in Spring Boot Rename tests to end on *IntegrationTest so they can be run on a more powerful Jenkins machine --- .../java/org/baeldung/jsoncomponent/UserCombinedSerializer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java index 302b0dce61..2001340197 100644 --- a/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java +++ b/spring-boot/src/main/java/org/baeldung/jsoncomponent/UserCombinedSerializer.java @@ -34,7 +34,6 @@ public class UserCombinedSerializer { } } - @JsonComponent public static class UserJsonDeserializer extends JsonDeserializer { @Override public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { From 806d2d87b7ef875e8810ab24a5ab2cd3d192a6dd Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 5 Apr 2017 13:12:33 -0500 Subject: [PATCH 257/291] BAEL-415: Custom Scope in Spring (#1578) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README * BAEL-415: Custom Scope * BAEL-415: Custom Scope - renamed classes to reflect TenantScope --- .../org/baeldung/customscope/TenantBean.java | 16 ++++ .../TenantBeanFactoryPostProcessor.java | 13 ++++ .../customscope/TenantBeansConfig.java | 21 ++++++ .../org/baeldung/customscope/TenantScope.java | 43 +++++++++++ .../customscope/TenantScopeConfig.java | 14 ++++ .../baeldung/customscope/TenantScopeTest.java | 74 +++++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBean.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantScope.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java create mode 100644 spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java new file mode 100644 index 0000000000..2d3049ebb9 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java @@ -0,0 +1,16 @@ +package org.baeldung.customscope; + +public class TenantBean { + + private final String name; + + public TenantBean(String name) { + this.name = name; + } + + public void sayHello() { + System.out.println(String.format("Hello from %s of type %s", + this.name, + this.getClass().getName())); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java new file mode 100644 index 0000000000..2757399fa6 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java @@ -0,0 +1,13 @@ +package org.baeldung.customscope; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; + +public class TenantBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { + factory.registerScope("tenant", new TenantScope()); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java new file mode 100644 index 0000000000..0e21ad9344 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java @@ -0,0 +1,21 @@ +package org.baeldung.customscope; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +public class TenantBeansConfig { + + @Scope(scopeName = "tenant") + @Bean + public TenantBean foo() { + return new TenantBean("foo"); + } + + @Scope(scopeName = "tenant") + @Bean + public TenantBean bar() { + return new TenantBean("bar"); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java b/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java new file mode 100644 index 0000000000..062d7ee890 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java @@ -0,0 +1,43 @@ +package org.baeldung.customscope; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; + +public class TenantScope implements Scope { + + private Map scopedObjects = Collections.synchronizedMap(new HashMap()); + private Map destructionCallbacks = Collections.synchronizedMap(new HashMap()); + + @Override + public Object get(String name, ObjectFactory objectFactory) { + if(!scopedObjects.containsKey(name)) { + scopedObjects.put(name, objectFactory.getObject()); + } + return scopedObjects.get(name); + } + + @Override + public Object remove(String name) { + destructionCallbacks.remove(name); + return scopedObjects.remove(name); + } + + @Override + public void registerDestructionCallback(String name, Runnable callback) { + destructionCallbacks.put(name, callback); + } + + @Override + public Object resolveContextualObject(String key) { + return null; + } + + @Override + public String getConversationId() { + return "tenant"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java b/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java new file mode 100644 index 0000000000..d1159b0f60 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java @@ -0,0 +1,14 @@ +package org.baeldung.customscope; + +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TenantScopeConfig { + + @Bean + public static BeanFactoryPostProcessor beanFactoryPostProcessor() { + return new TenantBeanFactoryPostProcessor(); + } +} diff --git a/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java b/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java new file mode 100644 index 0000000000..641e57bffd --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java @@ -0,0 +1,74 @@ +package org.baeldung.customscope; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class TenantScopeTest { + + @Test + public final void whenRegisterScopeAndBeans_thenContextContainsFooAndBar() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + try{ + ctx.register(TenantScopeConfig.class); + ctx.register(TenantBeansConfig.class); + ctx.refresh(); + + TenantBean foo = (TenantBean) ctx.getBean("foo", TenantBean.class); + foo.sayHello(); + TenantBean bar = (TenantBean) ctx.getBean("bar", TenantBean.class); + bar.sayHello(); + Map foos = ctx.getBeansOfType(TenantBean.class); + + assertThat(foo, not(equalTo(bar))); + assertThat(foos.size(), equalTo(2)); + assertTrue(foos.containsValue(foo)); + assertTrue(foos.containsValue(bar)); + + BeanDefinition fooDefinition = ctx.getBeanDefinition("foo"); + BeanDefinition barDefinition = ctx.getBeanDefinition("bar"); + + assertThat(fooDefinition.getScope(), equalTo("tenant")); + assertThat(barDefinition.getScope(), equalTo("tenant")); + } + finally { + ctx.close(); + } + } + + @Test + public final void whenComponentScan_thenContextContainsFooAndBar() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + try{ + ctx.scan("org.baeldung.customscope"); + ctx.refresh(); + + TenantBean foo = (TenantBean) ctx.getBean("foo", TenantBean.class); + foo.sayHello(); + TenantBean bar = (TenantBean) ctx.getBean("bar", TenantBean.class); + bar.sayHello(); + Map foos = ctx.getBeansOfType(TenantBean.class); + + assertThat(foo, not(equalTo(bar))); + assertThat(foos.size(), equalTo(2)); + assertTrue(foos.containsValue(foo)); + assertTrue(foos.containsValue(bar)); + + BeanDefinition fooDefinition = ctx.getBeanDefinition("foo"); + BeanDefinition barDefinition = ctx.getBeanDefinition("bar"); + + assertThat(fooDefinition.getScope(), equalTo("tenant")); + assertThat(barDefinition.getScope(), equalTo("tenant")); + } + finally { + ctx.close(); + } + } +} From 57fe1fce37d778e8de88aefb7e1b0784777e2bbd Mon Sep 17 00:00:00 2001 From: gitterjim-I Date: Wed, 5 Apr 2017 20:40:09 +0100 Subject: [PATCH 258/291] Change test names once more (#1596) * article Bael-667 initial commit. * Switch to use logging framework for output. * Make code more concise. Refactor as suggested. * modify test method names --- .../list/flattennestedlist/FlattenNestedListTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java index 285b217156..93962e7831 100644 --- a/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java +++ b/core-java/src/test/java/com/baeldung/list/flattennestedlist/FlattenNestedListTest.java @@ -17,7 +17,7 @@ public class FlattenNestedListTest { List> lol = asList(asList("one:one"), asList("two:one", "two:two", "two:three"), asList("three:one", "three:two", "three:three", "three:four")); @Test - public void givenNestedList_thenFlattenNestedListImperative() { + public void givenNestedList_thenFlattenImperatively() { List ls = flattenListOfListsImperatively(lol); assertNotNull(ls); @@ -27,7 +27,7 @@ public class FlattenNestedListTest { } @Test - public void givenNestedList_thenFlattenNestedListStream() { + public void givenNestedList_thenFlattenFunctionally() { List ls = flattenListOfListsStream(lol); assertNotNull(ls); From 2dfd789a4d36b3fb2d7cc8783ea42e6541d89178 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 5 Apr 2017 17:49:18 -0500 Subject: [PATCH 259/291] Update README files and cleanup (#1597) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README * BAEL-415: Custom Scope * BAEL-415: Custom Scope - renamed classes to reflect TenantScope * README file updates for BAEL-723, BAEL-763, and BAEL-415 --- .../java/com/baeldung/filter/CorsFilter.java | 22 ------------------- spring-all/README.md | 1 + spring-boot/README.MD | 1 + spring-data-rest/README.md | 1 + 4 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 resteasy/src/main/java/com/baeldung/filter/CorsFilter.java diff --git a/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java b/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java deleted file mode 100644 index 266707fb9f..0000000000 --- a/resteasy/src/main/java/com/baeldung/filter/CorsFilter.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.baeldung.filter; - -import java.io.IOException; - -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; -import javax.ws.rs.ext.Provider; - -@Provider -public class CorsFilter implements ContainerResponseFilter { - - @Override - public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) - throws IOException { - responseContext.getHeaders().add("Access-Control-Allow-Origin", "*"); - responseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); - responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true"); - responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); - } - -} diff --git a/spring-all/README.md b/spring-all/README.md index 047f1bd5f6..3493871c78 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -19,3 +19,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Introduction To Ehcache](http://www.baeldung.com/ehcache) - [A Guide to the Spring Task Scheduler](http://www.baeldung.com/spring-task-scheduler) - [Guide to Spring Retry](http://www.baeldung.com/spring-retry) +- [Custom Scope in Spring](http://www.baeldung.com/spring-custom-scope) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index 8aa5957bad..beb780ec3c 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -15,4 +15,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Guide to Spring WebUtils and ServletRequestUtils](http://www.baeldung.com/spring-webutils-servletrequestutils) - [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) - [Guide to Internationalization in Spring Boot](http://www.baeldung.com/spring-boot-internationalization) +- [Create a Custom FailureAnalyzer with Spring Boot](http://www.baeldung.com/spring-boot-failure-analyzer) diff --git a/spring-data-rest/README.md b/spring-data-rest/README.md index 241f2e3bcf..fa4a264abb 100644 --- a/spring-data-rest/README.md +++ b/spring-data-rest/README.md @@ -17,3 +17,4 @@ To view the running application, visit [http://localhost:8080](http://localhost: - [Guide to Spring Data REST Validators](http://www.baeldung.com/spring-data-rest-validators) - [Working with Relationships in Spring Data REST](http://www.baeldung.com/spring-data-rest-relationships) - [AngularJS CRUD Application with Spring Data REST](http://www.baeldung.com/angularjs-crud-with-spring-data-rest) +- [List of In-Memory Databases](http://www.baeldung.com/java-in-memory-databases) From ad0cd72dfd64ee235ebb05445106b4dd12fcb083 Mon Sep 17 00:00:00 2001 From: iaforek Date: Thu, 6 Apr 2017 01:20:04 +0100 Subject: [PATCH 260/291] BAEL-434 Spring Roo (#1589) * Code for Dependency Injection Article. * Added Java based configuration. Downloaded formatter.xml and reformatted all changed files. Manually changed tab into 4 spaces in XML configuration files. * BAEL-434 - Spring Roo project files generated by Spring Roo. No formatting applied. Added POM, java and resources folders. --- roo/pom.xml | 644 ++ .../java/com/baeldung/RooApplication.java | 23 + ...aJpaDetachableRepositoryConfiguration.java | 11 + ...ration_Roo_Jpa_Repository_Configuration.aj | 18 + .../baeldung/config/WebMvcConfiguration.java | 13 + ...figuration_Roo_ThymeleafUIConfiguration.aj | 110 + ...vcConfiguration_Roo_WebMvcConfiguration.aj | 72 + .../config/jackson/DomainModelModule.java | 11 + ...DomainModelModule_Roo_DomainModelModule.aj | 28 + .../main/java/com/baeldung/domain/Book.java | 58 + .../com/baeldung/domain/Book_Roo_Equals.aj | 41 + .../com/baeldung/domain/Book_Roo_JavaBean.aj | 100 + .../baeldung/domain/Book_Roo_Jpa_Entity.aj | 28 + .../com/baeldung/domain/Book_Roo_ToString.aj | 26 + .../baeldung/repository/BookRepository.java | 12 + .../repository/BookRepositoryCustom.java | 12 + ...ositoryCustom_Roo_Jpa_Repository_Custom.aj | 23 + .../repository/BookRepositoryImpl.java | 22 + ...kRepositoryImpl_Roo_Jpa_Repository_Impl.aj | 69 + .../BookRepository_Roo_Jpa_Repository.aj | 20 + .../com/baeldung/service/api/BookService.java | 12 + .../service/api/BookService_Roo_Service.aj | 95 + .../service/impl/BookServiceImpl.java | 12 + .../impl/BookServiceImpl_Roo_Service_Impl.aj | 177 + .../com/baeldung/web/BookDeserializer.java | 41 + ...BookDeserializer_Roo_EntityDeserializer.aj | 78 + .../java/com/baeldung/web/BookJsonMixin.java | 12 + .../BooksCollectionThymeleafController.java | 15 + ...ctionThymeleafController_Roo_Controller.aj | 35 + ...ectionThymeleafController_Roo_Thymeleaf.aj | 470 ++ .../BooksCollectionThymeleafLinkFactory.java | 11 + ...ionThymeleafLinkFactory_Roo_LinkFactory.aj | 122 + .../web/BooksItemThymeleafController.java | 15 + ...sItemThymeleafController_Roo_Controller.aj | 35 + ...ksItemThymeleafController_Roo_Thymeleaf.aj | 251 + .../web/BooksItemThymeleafLinkFactory.java | 11 + ...temThymeleafLinkFactory_Roo_LinkFactory.aj | 86 + .../java/com/baeldung/web/MainController.java | 11 + ...Controller_Roo_Thymeleaf_MainController.aj | 59 + .../web/reports/ExportingErrorException.java | 19 + .../web/reports/JasperReportsCsvExporter.java | 71 + .../web/reports/JasperReportsExporter.java | 41 + .../web/reports/JasperReportsPdfExporter.java | 71 + .../web/reports/JasperReportsXlsExporter.java | 77 + .../main/resources/application-dev.properties | 13 + roo/src/main/resources/application.properties | 8 + roo/src/main/resources/banner.txt | 9 + roo/src/main/resources/messages.properties | 146 + .../resources/static/public/css/springroo.css | 475 ++ .../resources/static/public/css/theme.css | 6914 +++++++++++++++++ .../public/fonts/fontawesome-webfont.eot | Bin 0 -> 75220 bytes .../public/fonts/fontawesome-webfont.svg | 685 ++ .../public/fonts/fontawesome-webfont.ttf | Bin 0 -> 150920 bytes .../public/fonts/fontawesome-webfont.woff | Bin 0 -> 89076 bytes .../public/fonts/fontawesome-webfont.woff2 | Bin 0 -> 70728 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../static/public/img/apple-touch-icon.png | Bin 0 -> 4723 bytes .../main/resources/static/public/img/en.png | Bin 0 -> 599 bytes .../main/resources/static/public/img/es.png | Bin 0 -> 469 bytes .../resources/static/public/img/favicon.ico | Bin 0 -> 26918 bytes .../main/resources/static/public/img/geo.png | Bin 0 -> 142350 bytes .../main/resources/static/public/img/logo.png | Bin 0 -> 1761 bytes .../static/public/img/owasp_logo.png | Bin 0 -> 4271 bytes .../static/public/img/springroo-logo.png | Bin 0 -> 25823 bytes .../static/public/js/dataTables.advanced.js | 1334 ++++ .../static/public/js/datatables-defaults.js | 29 + .../public/js/datetimepicker-defaults.js | 107 + .../static/public/js/inputmask-defaults.js | 30 + .../main/resources/static/public/js/main.js | 70 + .../static/public/js/moment-defaults.js | 88 + .../static/public/js/moment-locale-es.js | 73 + .../static/public/js/select2-defaults.js | 49 + .../static/public/js/validation-defaults.js | 233 + .../resources/templates/accessibility.html | 61 + .../resources/templates/books/create.html | 153 + .../main/resources/templates/books/edit.html | 171 + .../main/resources/templates/books/list.html | 98 + .../main/resources/templates/books/show.html | 86 + .../resources/templates/books/showInline.html | 67 + roo/src/main/resources/templates/error.html | 40 + .../resources/templates/fragments/footer.html | 51 + .../resources/templates/fragments/header.html | 21 + .../fragments/js/datatables-locale.js | 67 + .../templates/fragments/js/datatables.html | 78 + .../templates/fragments/js/select2.html | 16 + .../templates/fragments/languages.html | 33 + .../resources/templates/fragments/menu.html | 107 + .../fragments/modal-confirm-delete-batch.html | 34 + .../fragments/modal-confirm-delete.html | 35 + .../templates/fragments/modal-confirm.html | 32 + .../fragments/modal-export-empty-error.html | 20 + .../resources/templates/fragments/modal.html | 27 + .../templates/fragments/session-links.html | 46 + roo/src/main/resources/templates/index.html | 150 + .../layouts/default-layout-no-menu.html | 103 + .../templates/layouts/default-layout.html | 110 + .../layouts/default-list-layout.html | 121 + .../templates/layouts/home-layout.html | 104 + roo/src/main/resources/templates/login.html | 108 + .../templates/reports/export_default.jrxml | 59 + .../baeldung/constructordi/SpringRunner.java | 62 +- .../baeldung/constructordi/domain/Car.java | 42 +- .../java/com/baeldung/setterdi/Config.java | 35 + .../com/baeldung/setterdi/SpringRunner.java | 33 + .../com/baeldung/setterdi/domain/Car.java | 34 + .../com/baeldung/setterdi/domain/Engine.java | 22 + .../com/baeldung/setterdi/domain/Trailer.java | 11 + .../setterdi/domain/Transmission.java | 17 + .../src/main/resources/constructordi.xml | 20 + spring-core/src/main/resources/setterdi.xml | 24 + 114 files changed, 15965 insertions(+), 52 deletions(-) create mode 100644 roo/pom.xml create mode 100644 roo/src/main/java/com/baeldung/RooApplication.java create mode 100644 roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration.java create mode 100644 roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration_Roo_Jpa_Repository_Configuration.aj create mode 100644 roo/src/main/java/com/baeldung/config/WebMvcConfiguration.java create mode 100644 roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_ThymeleafUIConfiguration.aj create mode 100644 roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_WebMvcConfiguration.aj create mode 100644 roo/src/main/java/com/baeldung/config/jackson/DomainModelModule.java create mode 100644 roo/src/main/java/com/baeldung/config/jackson/DomainModelModule_Roo_DomainModelModule.aj create mode 100644 roo/src/main/java/com/baeldung/domain/Book.java create mode 100644 roo/src/main/java/com/baeldung/domain/Book_Roo_Equals.aj create mode 100644 roo/src/main/java/com/baeldung/domain/Book_Roo_JavaBean.aj create mode 100644 roo/src/main/java/com/baeldung/domain/Book_Roo_Jpa_Entity.aj create mode 100644 roo/src/main/java/com/baeldung/domain/Book_Roo_ToString.aj create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepository.java create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepositoryCustom.java create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepositoryCustom_Roo_Jpa_Repository_Custom.aj create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepositoryImpl.java create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepositoryImpl_Roo_Jpa_Repository_Impl.aj create mode 100644 roo/src/main/java/com/baeldung/repository/BookRepository_Roo_Jpa_Repository.aj create mode 100644 roo/src/main/java/com/baeldung/service/api/BookService.java create mode 100644 roo/src/main/java/com/baeldung/service/api/BookService_Roo_Service.aj create mode 100644 roo/src/main/java/com/baeldung/service/impl/BookServiceImpl.java create mode 100644 roo/src/main/java/com/baeldung/service/impl/BookServiceImpl_Roo_Service_Impl.aj create mode 100644 roo/src/main/java/com/baeldung/web/BookDeserializer.java create mode 100644 roo/src/main/java/com/baeldung/web/BookDeserializer_Roo_EntityDeserializer.aj create mode 100644 roo/src/main/java/com/baeldung/web/BookJsonMixin.java create mode 100644 roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController.java create mode 100644 roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Controller.aj create mode 100644 roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Thymeleaf.aj create mode 100644 roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory.java create mode 100644 roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory_Roo_LinkFactory.aj create mode 100644 roo/src/main/java/com/baeldung/web/BooksItemThymeleafController.java create mode 100644 roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Controller.aj create mode 100644 roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Thymeleaf.aj create mode 100644 roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory.java create mode 100644 roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory_Roo_LinkFactory.aj create mode 100644 roo/src/main/java/com/baeldung/web/MainController.java create mode 100644 roo/src/main/java/com/baeldung/web/MainController_Roo_Thymeleaf_MainController.aj create mode 100644 roo/src/main/java/com/baeldung/web/reports/ExportingErrorException.java create mode 100644 roo/src/main/java/com/baeldung/web/reports/JasperReportsCsvExporter.java create mode 100644 roo/src/main/java/com/baeldung/web/reports/JasperReportsExporter.java create mode 100644 roo/src/main/java/com/baeldung/web/reports/JasperReportsPdfExporter.java create mode 100644 roo/src/main/java/com/baeldung/web/reports/JasperReportsXlsExporter.java create mode 100644 roo/src/main/resources/application-dev.properties create mode 100644 roo/src/main/resources/application.properties create mode 100644 roo/src/main/resources/banner.txt create mode 100644 roo/src/main/resources/messages.properties create mode 100644 roo/src/main/resources/static/public/css/springroo.css create mode 100644 roo/src/main/resources/static/public/css/theme.css create mode 100644 roo/src/main/resources/static/public/fonts/fontawesome-webfont.eot create mode 100644 roo/src/main/resources/static/public/fonts/fontawesome-webfont.svg create mode 100644 roo/src/main/resources/static/public/fonts/fontawesome-webfont.ttf create mode 100644 roo/src/main/resources/static/public/fonts/fontawesome-webfont.woff create mode 100644 roo/src/main/resources/static/public/fonts/fontawesome-webfont.woff2 create mode 100644 roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.eot create mode 100644 roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.svg create mode 100644 roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.ttf create mode 100644 roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff create mode 100644 roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff2 create mode 100644 roo/src/main/resources/static/public/img/apple-touch-icon.png create mode 100644 roo/src/main/resources/static/public/img/en.png create mode 100644 roo/src/main/resources/static/public/img/es.png create mode 100644 roo/src/main/resources/static/public/img/favicon.ico create mode 100644 roo/src/main/resources/static/public/img/geo.png create mode 100644 roo/src/main/resources/static/public/img/logo.png create mode 100644 roo/src/main/resources/static/public/img/owasp_logo.png create mode 100644 roo/src/main/resources/static/public/img/springroo-logo.png create mode 100644 roo/src/main/resources/static/public/js/dataTables.advanced.js create mode 100644 roo/src/main/resources/static/public/js/datatables-defaults.js create mode 100644 roo/src/main/resources/static/public/js/datetimepicker-defaults.js create mode 100644 roo/src/main/resources/static/public/js/inputmask-defaults.js create mode 100644 roo/src/main/resources/static/public/js/main.js create mode 100644 roo/src/main/resources/static/public/js/moment-defaults.js create mode 100644 roo/src/main/resources/static/public/js/moment-locale-es.js create mode 100644 roo/src/main/resources/static/public/js/select2-defaults.js create mode 100644 roo/src/main/resources/static/public/js/validation-defaults.js create mode 100644 roo/src/main/resources/templates/accessibility.html create mode 100644 roo/src/main/resources/templates/books/create.html create mode 100644 roo/src/main/resources/templates/books/edit.html create mode 100644 roo/src/main/resources/templates/books/list.html create mode 100644 roo/src/main/resources/templates/books/show.html create mode 100644 roo/src/main/resources/templates/books/showInline.html create mode 100644 roo/src/main/resources/templates/error.html create mode 100644 roo/src/main/resources/templates/fragments/footer.html create mode 100644 roo/src/main/resources/templates/fragments/header.html create mode 100644 roo/src/main/resources/templates/fragments/js/datatables-locale.js create mode 100644 roo/src/main/resources/templates/fragments/js/datatables.html create mode 100644 roo/src/main/resources/templates/fragments/js/select2.html create mode 100644 roo/src/main/resources/templates/fragments/languages.html create mode 100644 roo/src/main/resources/templates/fragments/menu.html create mode 100644 roo/src/main/resources/templates/fragments/modal-confirm-delete-batch.html create mode 100644 roo/src/main/resources/templates/fragments/modal-confirm-delete.html create mode 100644 roo/src/main/resources/templates/fragments/modal-confirm.html create mode 100644 roo/src/main/resources/templates/fragments/modal-export-empty-error.html create mode 100644 roo/src/main/resources/templates/fragments/modal.html create mode 100644 roo/src/main/resources/templates/fragments/session-links.html create mode 100644 roo/src/main/resources/templates/index.html create mode 100644 roo/src/main/resources/templates/layouts/default-layout-no-menu.html create mode 100644 roo/src/main/resources/templates/layouts/default-layout.html create mode 100644 roo/src/main/resources/templates/layouts/default-list-layout.html create mode 100644 roo/src/main/resources/templates/layouts/home-layout.html create mode 100644 roo/src/main/resources/templates/login.html create mode 100644 roo/src/main/resources/templates/reports/export_default.jrxml create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/Config.java create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/SpringRunner.java create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/domain/Car.java create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/domain/Engine.java create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/domain/Trailer.java create mode 100644 spring-core/src/main/java/com/baeldung/setterdi/domain/Transmission.java create mode 100644 spring-core/src/main/resources/constructordi.xml create mode 100644 spring-core/src/main/resources/setterdi.xml diff --git a/roo/pom.xml b/roo/pom.xml new file mode 100644 index 0000000000..e1d69a3031 --- /dev/null +++ b/roo/pom.xml @@ -0,0 +1,644 @@ + + + + + io.spring.platform + platform-bom + Athens-RELEASE + + + 4.0.0 + com.baeldung + roo + 1.0.0.BUILD-SNAPSHOT + roo + + jar + + + 2.0.0.RC1 + 8 + UTF-8 + 1.8 + 1.5.4 + 1.4.1.RELEASE + 1.8 + 1.2.0.RC1 + 1.1.2 + 3.0.0.RELEASE + 2.0.0 + 2.0.1 + 5.0.11 + 1.0 + 3.3.6 + 1.10.12 + 1.10.11 + 1.1.2 + 1.1.2 + 2.0.2 + 2.0.2 + 1.1.2 + 1.1.2 + 1.1.2 + 2.0.0 + 2.5.4 + 4.6.2 + 1.12.3 + 3.3.1 + 1.15.0 + 2.13.0 + 4.0.3 + 0.1.0-beta.7 + 1.4.2 + 3.7.3 + 1.0.3 + + + + + + maven-snapshot-repository + Maven Snapshot Repository + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + spring-roo-repository + Spring Roo Repository + http://repo.spring.io/spring-roo + + + + + + + + + org.springframework.roo + org.springframework.roo.annotations + ${roo.version} + pom + provided + + + + io.springlets + springlets-data-jpa + ${springlets.version} + + + io.springlets + springlets-data-commons + ${springlets.version} + + + io.springlets + springlets-context + ${springlets.version} + + + org.springframework.roo + org.springframework.roo.querydsl.processor + 2.0.0.RELEASE + + + io.tracee.binding + tracee-springmvc + ${tracee.version} + + + io.springlets + springlets-boot-starter-web + ${springlets.version} + + + com.github.mxab.thymeleaf.extras + thymeleaf-extras-data-attribute + ${thymeleaf-data-dialect.version} + + + ar.com.fdvs + DynamicJasper + ${dynamicjasper.version} + + + ar.com.fdvs + DynamicJasper-core-fonts + ${dynamicjasper-fonts.version} + + + org.webjars.bower + bootstrap + ${bootstrap.version} + + + org.webjars.bower + datatables + ${datatables.version} + + + org.webjars.bower + datatables.net-bs + ${datatables-bs.version} + + + org.webjars.bower + datatables.net-buttons + ${datatables-buttons.version} + + + org.webjars.bower + datatables.net-buttons-bs + ${datatables-buttons-bs.version} + + + org.webjars.bower + datatables.net-responsive + ${datatables-responsive.version} + + + org.webjars.bower + datatables.net-responsive-bs + ${datatables-responsive-bs.version} + + + org.webjars.bower + datatables.net-select + ${datatables-select.version} + + + org.webjars.bower + datatables.net-select-bs + ${datatables-select-bs.version} + + + org.webjars.npm + jquery-datatables-checkboxes + ${datatables-checkboxes.version} + + + org.webjars.npm + jquery + + + org.webjars.npm + datatables.net + + + + + org.webjars.bower + github-com-julmot-datatables-mark-js + ${datatables-mark.version} + + + org.webjars.bower + datetimepicker + ${datetimepicker.version} + + + org.webjars.bower + font-awesome + ${fontawesome.version} + + + org.webjars.bower + jquery + ${jquery.version} + + + org.webjars + jquery.inputmask + ${jquery-inputmask.version} + + + org.webjars + jquery + + + + + org.webjars.bower + jquery-validation + ${jquery-validation.version} + + + org.webjars.bower + momentjs + ${momentjs.version} + + + org.webjars.bower + select2 + ${select2.version} + + + org.webjars.bower + select2-bootstrap-theme + ${select2-bootstrap-theme.version} + + + org.webjars + respond + ${respond.version} + + + org.webjars + html5shiv + ${html5shiv.version} + + + org.webjars.bower + ie10-viewport-bug-workaround + ${bootstrap.ie10-viewport-bug-workaround.version} + + + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-devtools + true + + + + + org.springframework.roo + org.springframework.roo.annotations + pom + + + + + org.aspectj + aspectjrt + + + + + org.apache.commons + commons-lang3 + + + + + org.assertj + assertj-core + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-jdbc + provided + + + org.hsqldb + hsqldb + provided + + + io.springlets + springlets-data-jpa + + + io.springlets + springlets-data-commons + + + io.springlets + springlets-context + + + javax.validation + validation-api + + + com.querydsl + querydsl-jpa + + + org.springframework.roo + org.springframework.roo.querydsl.processor + + + org.springframework.boot + spring-boot-starter-web + + + joda-time + joda-time + + + io.tracee.binding + tracee-springmvc + + + io.springlets + springlets-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + + + com.github.mxab.thymeleaf.extras + thymeleaf-extras-data-attribute + + + ar.com.fdvs + DynamicJasper + + + ar.com.fdvs + DynamicJasper-core-fonts + + + org.apache.poi + poi + + + org.springframework + spring-context-support + + + org.webjars + webjars-locator + + + org.webjars.bower + bootstrap + + + org.webjars.bower + datatables + + + org.webjars.bower + datatables.net-bs + + + org.webjars.bower + datatables.net-buttons + + + org.webjars.bower + datatables.net-buttons-bs + + + org.webjars.bower + datatables.net-responsive + + + org.webjars.bower + datatables.net-responsive-bs + + + org.webjars.bower + datatables.net-select + + + org.webjars.bower + datatables.net-select-bs + + + org.webjars.npm + jquery-datatables-checkboxes + + + org.webjars.bower + github-com-julmot-datatables-mark-js + + + org.webjars.bower + datetimepicker + + + org.webjars.bower + font-awesome + + + org.webjars.bower + jquery + + + org.webjars + jquery.inputmask + + + org.webjars.bower + jquery-validation + + + org.webjars.bower + momentjs + + + org.webjars.bower + select2 + + + org.webjars.bower + select2-bootstrap-theme + + + org.webjars + respond + + + org.webjars + html5shiv + + + org.webjars.bower + ie10-viewport-bug-workaround + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + exec + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + false + + + + + org.codehaus.mojo + aspectj-maven-plugin + ${aspectj.plugin.version} + + ${java.version} + ${java.version} + ignore + ${java.version} + UTF-8 + + + + process-sources + + compile + test-compile + + + + + + org.aspectj + aspectjtools + ${aspectj.version} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*_Roo_* + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + --base-dir ${project.basedir} + --attribute + "projectName=${project.name}" + --attribute + "projectVersion=${project.version}" + --attribute "doctype=book" + + + ${project.groupId}:* + + org.asciidoctor.Asciidoclet + + org.asciidoctor + asciidoclet + ${asciidoclet.version} + + true + true + + http://docs.oracle.com/javase/${java.version}/docs/api/ + http://docs.oracle.com/javaee/${java.product.version}/api/ + http://docs.spring.io/spring-framework/docs/${spring.version}/javadoc-api/ + http://docs.spring.io/spring-boot/docs/${spring-boot.version}/api/ + http://fasterxml.github.io/jackson-core/javadoc/2.8/ + http://fasterxml.github.io/jackson-databind/javadoc/2.8 + http://cxf.apache.org/javadoc/latest-3.1.x/ + + src/main/java/overview.adoc + private + ${java.version} + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + + process + + + target/generated-sources/java + + org.springframework.roo.querydsl.processor.RooAnnotationProcessor + + + + + + + + com.querydsl + querydsl-apt + ${querydsl.version} + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.codehaus.mojo + aspectj-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + com.mysema.maven + apt-maven-plugin + + + + + diff --git a/roo/src/main/java/com/baeldung/RooApplication.java b/roo/src/main/java/com/baeldung/RooApplication.java new file mode 100644 index 0000000000..96f5a4ccc2 --- /dev/null +++ b/roo/src/main/java/com/baeldung/RooApplication.java @@ -0,0 +1,23 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * = RooApplication + * + * TODO Auto-generated class documentation + * + */ +@SpringBootApplication +public class RooApplication { + + /** + * TODO Auto-generated method documentation + * + * @param args + */ + public static void main(String[] args) { + SpringApplication.run(RooApplication.class, args); + } +} \ No newline at end of file diff --git a/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration.java b/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration.java new file mode 100644 index 0000000000..98916a9412 --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration.java @@ -0,0 +1,11 @@ +package com.baeldung.config; +import org.springframework.roo.addon.layers.repository.jpa.annotations.RooJpaRepositoryConfiguration; + +/** + * = SpringDataJpaDetachableRepositoryConfiguration + TODO Auto-generated class documentation + * + */ +@RooJpaRepositoryConfiguration +public class SpringDataJpaDetachableRepositoryConfiguration { +} diff --git a/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration_Roo_Jpa_Repository_Configuration.aj b/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration_Roo_Jpa_Repository_Configuration.aj new file mode 100644 index 0000000000..7f54997ddb --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/SpringDataJpaDetachableRepositoryConfiguration_Roo_Jpa_Repository_Configuration.aj @@ -0,0 +1,18 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.config; + +import com.baeldung.RooApplication; +import com.baeldung.config.SpringDataJpaDetachableRepositoryConfiguration; +import io.springlets.data.jpa.repository.support.DetachableJpaRepositoryImpl; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +privileged aspect SpringDataJpaDetachableRepositoryConfiguration_Roo_Jpa_Repository_Configuration { + + declare @type: SpringDataJpaDetachableRepositoryConfiguration: @Configuration; + + declare @type: SpringDataJpaDetachableRepositoryConfiguration: @EnableJpaRepositories(repositoryBaseClass = DetachableJpaRepositoryImpl.class, basePackageClasses = RooApplication.class); + +} diff --git a/roo/src/main/java/com/baeldung/config/WebMvcConfiguration.java b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration.java new file mode 100644 index 0000000000..5276300091 --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration.java @@ -0,0 +1,13 @@ +package com.baeldung.config; +import org.springframework.roo.addon.web.mvc.controller.annotations.config.RooWebMvcConfiguration; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooWebMvcThymeleafUIConfiguration; + +/** + * = WebMvcConfiguration + TODO Auto-generated class documentation + * + */ +@RooWebMvcConfiguration(defaultLanguage = "en") +@RooWebMvcThymeleafUIConfiguration +public class WebMvcConfiguration { +} diff --git a/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_ThymeleafUIConfiguration.aj b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_ThymeleafUIConfiguration.aj new file mode 100644 index 0000000000..c21cb6b68c --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_ThymeleafUIConfiguration.aj @@ -0,0 +1,110 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.config; + +import com.baeldung.config.WebMvcConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Bean; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring4.view.ThymeleafViewResolver; +import org.thymeleaf.templatemode.TemplateMode; + +privileged aspect WebMvcConfiguration_Roo_ThymeleafUIConfiguration { + + declare parents: WebMvcConfiguration implements ApplicationContextAware; + + /** + * TODO Auto-generated attribute documentation + * + */ + @Autowired + private ThymeleafProperties WebMvcConfiguration.thymeleafProperties; + + /** + * TODO Auto-generated attribute documentation + * + */ + @Autowired + private TemplateEngine WebMvcConfiguration.templateEngine; + + /** + * TODO Auto-generated attribute documentation + * + */ + private ApplicationContext WebMvcConfiguration.applicationContext; + + /** + * TODO Auto-generated method documentation + * + * @return ThymeleafProperties + */ + public ThymeleafProperties WebMvcConfiguration.getThymeleafProperties() { + return thymeleafProperties; + } + + /** + * TODO Auto-generated method documentation + * + * @return TemplateEngine + */ + public TemplateEngine WebMvcConfiguration.getTemplateEngine() { + return templateEngine; + } + + /** + * TODO Auto-generated method documentation + * + * @return ApplicationContext + */ + public ApplicationContext WebMvcConfiguration.getApplicationContext() { + return applicationContext; + } + + /** + * TODO Auto-generated method documentation + * + * @param applicationContext + */ + public void WebMvcConfiguration.setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + /** + * TODO Auto-generated method documentation + * + * @return ThymeleafViewResolver + */ + @Bean + public ThymeleafViewResolver WebMvcConfiguration.javascriptThymeleafViewResolver() { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(getTemplateEngine()); + resolver.setCharacterEncoding("UTF-8"); + resolver.setContentType("application/javascript"); + resolver.setViewNames(new String[] {"*.js"}); + resolver.setCache(getThymeleafProperties().isCache()); + return resolver; + } + + /** + * TODO Auto-generated method documentation + * + * @return SpringResourceTemplateResolver + */ + @Bean + public SpringResourceTemplateResolver WebMvcConfiguration.javascriptTemplateResolver() { + SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); + resolver.setApplicationContext(getApplicationContext()); + resolver.setPrefix("classpath:/templates/fragments/js/"); + resolver.setTemplateMode(TemplateMode.JAVASCRIPT); + resolver.setCharacterEncoding("UTF-8"); + resolver.setCheckExistence(true); + resolver.setCacheable(getThymeleafProperties().isCache()); + return resolver; + } + +} diff --git a/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_WebMvcConfiguration.aj b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_WebMvcConfiguration.aj new file mode 100644 index 0000000000..8031c83ca3 --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/WebMvcConfiguration_Roo_WebMvcConfiguration.aj @@ -0,0 +1,72 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.config; + +import com.baeldung.config.WebMvcConfiguration; +import io.tracee.binding.springmvc.TraceeInterceptor; +import java.lang.Override; +import java.util.Locale; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +privileged aspect WebMvcConfiguration_Roo_WebMvcConfiguration { + + declare parents: WebMvcConfiguration extends WebMvcConfigurerAdapter; + + declare @type: WebMvcConfiguration: @Configuration; + + /** + * TODO Auto-generated method documentation + * + * @return LocalValidatorFactoryBean + */ + @Primary + @Bean + public LocalValidatorFactoryBean WebMvcConfiguration.validator() { + return new LocalValidatorFactoryBean(); + } + + /** + * TODO Auto-generated method documentation + * + * @return LocaleResolver + */ + @Bean + public LocaleResolver WebMvcConfiguration.localeResolver() { + SessionLocaleResolver localeResolver = new SessionLocaleResolver(); + localeResolver.setDefaultLocale(new Locale("en")); + return localeResolver; + } + + /** + * TODO Auto-generated method documentation + * + * @return LocaleChangeInterceptor + */ + @Bean + public LocaleChangeInterceptor WebMvcConfiguration.localeChangeInterceptor() { + LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("lang"); + return localeChangeInterceptor; + } + + /** + * TODO Auto-generated method documentation + * + * @param registry + */ + @Override + public void WebMvcConfiguration.addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + registry.addInterceptor(new TraceeInterceptor()); + } + +} diff --git a/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule.java b/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule.java new file mode 100644 index 0000000000..2a66a48846 --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule.java @@ -0,0 +1,11 @@ +package com.baeldung.config.jackson; +import org.springframework.roo.addon.web.mvc.controller.annotations.config.RooDomainModelModule; + +/** + * = DomainModelModule + TODO Auto-generated class documentation + * + */ +@RooDomainModelModule +public class DomainModelModule { +} diff --git a/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule_Roo_DomainModelModule.aj b/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule_Roo_DomainModelModule.aj new file mode 100644 index 0000000000..4683a3fe2d --- /dev/null +++ b/roo/src/main/java/com/baeldung/config/jackson/DomainModelModule_Roo_DomainModelModule.aj @@ -0,0 +1,28 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.config.jackson; + +import com.baeldung.config.jackson.DomainModelModule; +import com.baeldung.domain.Book; +import com.baeldung.web.BookJsonMixin; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.springframework.boot.jackson.JsonComponent; + +privileged aspect DomainModelModule_Roo_DomainModelModule { + + declare parents: DomainModelModule extends SimpleModule; + + declare @type: DomainModelModule: @JsonComponent; + + /** + * TODO Auto-generated constructor documentation + * + */ + public DomainModelModule.new() { + // Mixin registration + + setMixInAnnotation(Book.class, BookJsonMixin.class); + } + +} diff --git a/roo/src/main/java/com/baeldung/domain/Book.java b/roo/src/main/java/com/baeldung/domain/Book.java new file mode 100644 index 0000000000..99e7b894e6 --- /dev/null +++ b/roo/src/main/java/com/baeldung/domain/Book.java @@ -0,0 +1,58 @@ +package com.baeldung.domain; +import org.springframework.roo.addon.javabean.annotations.RooEquals; +import org.springframework.roo.addon.javabean.annotations.RooJavaBean; +import org.springframework.roo.addon.javabean.annotations.RooToString; +import org.springframework.roo.addon.jpa.annotations.entity.RooJpaEntity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Version; +import javax.validation.constraints.NotNull; + +/** + * = Book + TODO Auto-generated class documentation + * + */ +@RooJavaBean +@RooToString +@RooJpaEntity +@RooEquals(isJpaEntity = true) +public class Book { + + /** + * TODO Auto-generated attribute documentation + * + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + /** + * TODO Auto-generated attribute documentation + * + */ + @Version + private Integer version; + + /** + * TODO Auto-generated attribute documentation + * + */ + @NotNull + private String title; + + /** + * TODO Auto-generated attribute documentation + * + */ + @NotNull + private String author; + + /** + * TODO Auto-generated attribute documentation + * + */ + @NotNull + private String isbn; +} diff --git a/roo/src/main/java/com/baeldung/domain/Book_Roo_Equals.aj b/roo/src/main/java/com/baeldung/domain/Book_Roo_Equals.aj new file mode 100644 index 0000000000..51d6069eb0 --- /dev/null +++ b/roo/src/main/java/com/baeldung/domain/Book_Roo_Equals.aj @@ -0,0 +1,41 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.domain; + +import com.baeldung.domain.Book; +import java.util.Objects; + +privileged aspect Book_Roo_Equals { + + /** + * This `equals` implementation is specific for JPA entities and uses + * the entity identifier for it, following the article in + * https://vladmihalcea.com/2016/06/06/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ + * + * @param obj + * @return Boolean + */ + public boolean Book.equals(Object obj) { + if (this == obj) { + return true; + } + // instanceof is false if the instance is null + if (!(obj instanceof Book)) { + return false; + } + return getId() != null && Objects.equals(getId(), ((Book) obj).getId()); + } + + /** + * This `hashCode` implementation is specific for JPA entities and uses a fixed `int` value to be able + * to identify the entity in collections after a new id is assigned to the entity, following the article in + * https://vladmihalcea.com/2016/06/06/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/ + * + * @return Integer + */ + public int Book.hashCode() { + return 31; + } + +} diff --git a/roo/src/main/java/com/baeldung/domain/Book_Roo_JavaBean.aj b/roo/src/main/java/com/baeldung/domain/Book_Roo_JavaBean.aj new file mode 100644 index 0000000000..3ea375ce12 --- /dev/null +++ b/roo/src/main/java/com/baeldung/domain/Book_Roo_JavaBean.aj @@ -0,0 +1,100 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.domain; + +import com.baeldung.domain.Book; + +privileged aspect Book_Roo_JavaBean { + + /** + * TODO Auto-generated method documentation + * + * @return Long + */ + public Long Book.getId() { + return this.id; + } + + /** + * TODO Auto-generated method documentation + * + * @param id + */ + public void Book.setId(Long id) { + this.id = id; + } + + /** + * TODO Auto-generated method documentation + * + * @return Integer + */ + public Integer Book.getVersion() { + return this.version; + } + + /** + * TODO Auto-generated method documentation + * + * @param version + */ + public void Book.setVersion(Integer version) { + this.version = version; + } + + /** + * TODO Auto-generated method documentation + * + * @return String + */ + public String Book.getTitle() { + return this.title; + } + + /** + * TODO Auto-generated method documentation + * + * @param title + */ + public void Book.setTitle(String title) { + this.title = title; + } + + /** + * TODO Auto-generated method documentation + * + * @return String + */ + public String Book.getAuthor() { + return this.author; + } + + /** + * TODO Auto-generated method documentation + * + * @param author + */ + public void Book.setAuthor(String author) { + this.author = author; + } + + /** + * TODO Auto-generated method documentation + * + * @return String + */ + public String Book.getIsbn() { + return this.isbn; + } + + /** + * TODO Auto-generated method documentation + * + * @param isbn + */ + public void Book.setIsbn(String isbn) { + this.isbn = isbn; + } + +} diff --git a/roo/src/main/java/com/baeldung/domain/Book_Roo_Jpa_Entity.aj b/roo/src/main/java/com/baeldung/domain/Book_Roo_Jpa_Entity.aj new file mode 100644 index 0000000000..739a00e058 --- /dev/null +++ b/roo/src/main/java/com/baeldung/domain/Book_Roo_Jpa_Entity.aj @@ -0,0 +1,28 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.domain; + +import com.baeldung.domain.Book; +import io.springlets.format.EntityFormat; +import javax.persistence.Entity; + +privileged aspect Book_Roo_Jpa_Entity { + + declare @type: Book: @Entity; + + declare @type: Book: @EntityFormat; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String Book.ITERABLE_TO_ADD_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String Book.ITERABLE_TO_REMOVE_CANT_BE_NULL_MESSAGE = "The given Iterable of items to add can't be null!"; + +} diff --git a/roo/src/main/java/com/baeldung/domain/Book_Roo_ToString.aj b/roo/src/main/java/com/baeldung/domain/Book_Roo_ToString.aj new file mode 100644 index 0000000000..69083eaf9e --- /dev/null +++ b/roo/src/main/java/com/baeldung/domain/Book_Roo_ToString.aj @@ -0,0 +1,26 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.domain; + +import com.baeldung.domain.Book; + +privileged aspect Book_Roo_ToString { + + /** + * TODO Auto-generated method documentation + * + * @return String + */ + public String Book.toString() { + return "Book {" + + "id='" + id + '\'' + + ", version='" + version + '\'' + + ", title='" + title + '\'' + + ", author='" + author + '\'' + + ", isbn='" + isbn + '\'' + + ", ITERABLE_TO_ADD_CANT_BE_NULL_MESSAGE='" + ITERABLE_TO_ADD_CANT_BE_NULL_MESSAGE + '\'' + + ", ITERABLE_TO_REMOVE_CANT_BE_NULL_MESSAGE='" + ITERABLE_TO_REMOVE_CANT_BE_NULL_MESSAGE + '\'' + "}" + super.toString(); + } + +} diff --git a/roo/src/main/java/com/baeldung/repository/BookRepository.java b/roo/src/main/java/com/baeldung/repository/BookRepository.java new file mode 100644 index 0000000000..78567c1c92 --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.repository; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.layers.repository.jpa.annotations.RooJpaRepository; + +/** + * = BookRepository + TODO Auto-generated class documentation + * + */ +@RooJpaRepository(entity = Book.class) +public interface BookRepository { +} diff --git a/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom.java b/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom.java new file mode 100644 index 0000000000..44469e31b6 --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom.java @@ -0,0 +1,12 @@ +package com.baeldung.repository; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.layers.repository.jpa.annotations.RooJpaRepositoryCustom; + +/** + * = BookRepositoryCustom + TODO Auto-generated class documentation + * + */ +@RooJpaRepositoryCustom(entity = Book.class) +public interface BookRepositoryCustom { +} diff --git a/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom_Roo_Jpa_Repository_Custom.aj b/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom_Roo_Jpa_Repository_Custom.aj new file mode 100644 index 0000000000..7cb44f84a1 --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepositoryCustom_Roo_Jpa_Repository_Custom.aj @@ -0,0 +1,23 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.repository; + +import com.baeldung.domain.Book; +import com.baeldung.repository.BookRepositoryCustom; +import io.springlets.data.domain.GlobalSearch; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +privileged aspect BookRepositoryCustom_Roo_Jpa_Repository_Custom { + + /** + * TODO Auto-generated method documentation + * + * @param globalSearch + * @param pageable + * @return Page + */ + public abstract Page BookRepositoryCustom.findAll(GlobalSearch globalSearch, Pageable pageable); + +} diff --git a/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl.java b/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl.java new file mode 100644 index 0000000000..e59ff8ab0e --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl.java @@ -0,0 +1,22 @@ +package com.baeldung.repository; + +import io.springlets.data.jpa.repository.support.QueryDslRepositorySupportExt; +import org.springframework.roo.addon.layers.repository.jpa.annotations.RooJpaRepositoryCustomImpl; +import com.baeldung.domain.Book; + +/** + * = BookRepositoryImpl + * + * TODO Auto-generated class documentation + * + */ +@RooJpaRepositoryCustomImpl(repository = BookRepositoryCustom.class) +public class BookRepositoryImpl extends QueryDslRepositorySupportExt { + + /** + * TODO Auto-generated constructor documentation + */ + BookRepositoryImpl() { + super(Book.class); + } +} \ No newline at end of file diff --git a/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl_Roo_Jpa_Repository_Impl.aj b/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl_Roo_Jpa_Repository_Impl.aj new file mode 100644 index 0000000000..9e3db3e1f4 --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepositoryImpl_Roo_Jpa_Repository_Impl.aj @@ -0,0 +1,69 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.repository; + +import com.baeldung.domain.Book; +import com.baeldung.domain.QBook; +import com.baeldung.repository.BookRepositoryCustom; +import com.baeldung.repository.BookRepositoryImpl; +import com.querydsl.core.types.Path; +import com.querydsl.jpa.JPQLQuery; +import io.springlets.data.domain.GlobalSearch; +import io.springlets.data.jpa.repository.support.QueryDslRepositorySupportExt.AttributeMappingBuilder; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; + +privileged aspect BookRepositoryImpl_Roo_Jpa_Repository_Impl { + + declare parents: BookRepositoryImpl implements BookRepositoryCustom; + + declare @type: BookRepositoryImpl: @Transactional(readOnly = true); + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BookRepositoryImpl.TITLE = "title"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BookRepositoryImpl.AUTHOR = "author"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BookRepositoryImpl.ISBN = "isbn"; + + /** + * TODO Auto-generated method documentation + * + * @param globalSearch + * @param pageable + * @return Page + */ + public Page BookRepositoryImpl.findAll(GlobalSearch globalSearch, Pageable pageable) { + + QBook book = QBook.book; + + JPQLQuery query = from(book); + + Path[] paths = new Path[] {book.title,book.author,book.isbn}; + applyGlobalSearch(globalSearch, query, paths); + + AttributeMappingBuilder mapping = buildMapper() + .map(TITLE, book.title) + .map(AUTHOR, book.author) + .map(ISBN, book.isbn); + + applyPagination(pageable, query, mapping); + applyOrderById(query); + + return loadPage(query, pageable, book); + } + +} diff --git a/roo/src/main/java/com/baeldung/repository/BookRepository_Roo_Jpa_Repository.aj b/roo/src/main/java/com/baeldung/repository/BookRepository_Roo_Jpa_Repository.aj new file mode 100644 index 0000000000..2f57062054 --- /dev/null +++ b/roo/src/main/java/com/baeldung/repository/BookRepository_Roo_Jpa_Repository.aj @@ -0,0 +1,20 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.repository; + +import com.baeldung.domain.Book; +import com.baeldung.repository.BookRepository; +import com.baeldung.repository.BookRepositoryCustom; +import io.springlets.data.jpa.repository.DetachableJpaRepository; +import org.springframework.transaction.annotation.Transactional; + +privileged aspect BookRepository_Roo_Jpa_Repository { + + declare parents: BookRepository extends DetachableJpaRepository; + + declare parents: BookRepository extends BookRepositoryCustom; + + declare @type: BookRepository: @Transactional(readOnly = true); + +} diff --git a/roo/src/main/java/com/baeldung/service/api/BookService.java b/roo/src/main/java/com/baeldung/service/api/BookService.java new file mode 100644 index 0000000000..212ee1cdfc --- /dev/null +++ b/roo/src/main/java/com/baeldung/service/api/BookService.java @@ -0,0 +1,12 @@ +package com.baeldung.service.api; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.layers.service.annotations.RooService; + +/** + * = BookService + TODO Auto-generated class documentation + * + */ +@RooService(entity = Book.class) +public interface BookService { +} diff --git a/roo/src/main/java/com/baeldung/service/api/BookService_Roo_Service.aj b/roo/src/main/java/com/baeldung/service/api/BookService_Roo_Service.aj new file mode 100644 index 0000000000..d5698ffb37 --- /dev/null +++ b/roo/src/main/java/com/baeldung/service/api/BookService_Roo_Service.aj @@ -0,0 +1,95 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.service.api; + +import com.baeldung.domain.Book; +import com.baeldung.service.api.BookService; +import io.springlets.data.domain.GlobalSearch; +import io.springlets.format.EntityResolver; +import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +privileged aspect BookService_Roo_Service { + + declare parents: BookService extends EntityResolver; + + /** + * TODO Auto-generated method documentation + * + * @param id + * @return Book + */ + public abstract Book BookService.findOne(Long id); + + /** + * TODO Auto-generated method documentation + * + * @param book + */ + public abstract void BookService.delete(Book book); + + /** + * TODO Auto-generated method documentation + * + * @param entities + * @return List + */ + public abstract List BookService.save(Iterable entities); + + /** + * TODO Auto-generated method documentation + * + * @param ids + */ + public abstract void BookService.delete(Iterable ids); + + /** + * TODO Auto-generated method documentation + * + * @param entity + * @return Book + */ + public abstract Book BookService.save(Book entity); + + /** + * TODO Auto-generated method documentation + * + * @param id + * @return Book + */ + public abstract Book BookService.findOneForUpdate(Long id); + + /** + * TODO Auto-generated method documentation + * + * @param ids + * @return List + */ + public abstract List BookService.findAll(Iterable ids); + + /** + * TODO Auto-generated method documentation + * + * @return List + */ + public abstract List BookService.findAll(); + + /** + * TODO Auto-generated method documentation + * + * @return Long + */ + public abstract long BookService.count(); + + /** + * TODO Auto-generated method documentation + * + * @param globalSearch + * @param pageable + * @return Page + */ + public abstract Page BookService.findAll(GlobalSearch globalSearch, Pageable pageable); + +} diff --git a/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl.java b/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl.java new file mode 100644 index 0000000000..1b44547629 --- /dev/null +++ b/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl.java @@ -0,0 +1,12 @@ +package com.baeldung.service.impl; +import com.baeldung.service.api.BookService; +import org.springframework.roo.addon.layers.service.annotations.RooServiceImpl; + +/** + * = BookServiceImpl + TODO Auto-generated class documentation + * + */ +@RooServiceImpl(service = BookService.class) +public class BookServiceImpl implements BookService { +} diff --git a/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl_Roo_Service_Impl.aj b/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl_Roo_Service_Impl.aj new file mode 100644 index 0000000000..8f9fb846aa --- /dev/null +++ b/roo/src/main/java/com/baeldung/service/impl/BookServiceImpl_Roo_Service_Impl.aj @@ -0,0 +1,177 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.service.impl; + +import com.baeldung.domain.Book; +import com.baeldung.repository.BookRepository; +import com.baeldung.service.impl.BookServiceImpl; +import io.springlets.data.domain.GlobalSearch; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +privileged aspect BookServiceImpl_Roo_Service_Impl { + + declare @type: BookServiceImpl: @Service; + + declare @type: BookServiceImpl: @Transactional(readOnly = true); + + /** + * TODO Auto-generated attribute documentation + * + */ + private BookRepository BookServiceImpl.bookRepository; + + /** + * TODO Auto-generated constructor documentation + * + * @param bookRepository + */ + @Autowired + public BookServiceImpl.new(BookRepository bookRepository) { + setBookRepository(bookRepository); + } + + /** + * TODO Auto-generated method documentation + * + * @return BookRepository + */ + public BookRepository BookServiceImpl.getBookRepository() { + return bookRepository; + } + + /** + * TODO Auto-generated method documentation + * + * @param bookRepository + */ + public void BookServiceImpl.setBookRepository(BookRepository bookRepository) { + this.bookRepository = bookRepository; + } + + /** + * TODO Auto-generated method documentation + * + * @param book + */ + @Transactional + public void BookServiceImpl.delete(Book book) { + getBookRepository().delete(book); + } + + /** + * TODO Auto-generated method documentation + * + * @param entities + * @return List + */ + @Transactional + public List BookServiceImpl.save(Iterable entities) { + return getBookRepository().save(entities); + } + + /** + * TODO Auto-generated method documentation + * + * @param ids + */ + @Transactional + public void BookServiceImpl.delete(Iterable ids) { + List toDelete = getBookRepository().findAll(ids); + getBookRepository().deleteInBatch(toDelete); + } + + /** + * TODO Auto-generated method documentation + * + * @param entity + * @return Book + */ + @Transactional + public Book BookServiceImpl.save(Book entity) { + return getBookRepository().save(entity); + } + + /** + * TODO Auto-generated method documentation + * + * @param id + * @return Book + */ + public Book BookServiceImpl.findOne(Long id) { + return getBookRepository().findOne(id); + } + + /** + * TODO Auto-generated method documentation + * + * @param id + * @return Book + */ + public Book BookServiceImpl.findOneForUpdate(Long id) { + return getBookRepository().findOneDetached(id); + } + + /** + * TODO Auto-generated method documentation + * + * @param ids + * @return List + */ + public List BookServiceImpl.findAll(Iterable ids) { + return getBookRepository().findAll(ids); + } + + /** + * TODO Auto-generated method documentation + * + * @return List + */ + public List BookServiceImpl.findAll() { + return getBookRepository().findAll(); + } + + /** + * TODO Auto-generated method documentation + * + * @return Long + */ + public long BookServiceImpl.count() { + return getBookRepository().count(); + } + + /** + * TODO Auto-generated method documentation + * + * @param globalSearch + * @param pageable + * @return Page + */ + public Page BookServiceImpl.findAll(GlobalSearch globalSearch, Pageable pageable) { + return getBookRepository().findAll(globalSearch, pageable); + } + + /** + * TODO Auto-generated method documentation + * + * @return Class + */ + public Class BookServiceImpl.getEntityType() { + return Book.class; + } + + /** + * TODO Auto-generated method documentation + * + * @return Class + */ + public Class BookServiceImpl.getIdType() { + return Long.class; + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BookDeserializer.java b/roo/src/main/java/com/baeldung/web/BookDeserializer.java new file mode 100644 index 0000000000..38c447e580 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BookDeserializer.java @@ -0,0 +1,41 @@ +package com.baeldung.web; +import com.baeldung.domain.Book; +import com.baeldung.service.api.BookService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.jackson.JsonObjectDeserializer; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.convert.ConversionService; +import org.springframework.roo.addon.web.mvc.controller.annotations.config.RooDeserializer; + +/** + * = BookDeserializer + TODO Auto-generated class documentation + * + */ +@RooDeserializer(entity = Book.class) +public class BookDeserializer extends JsonObjectDeserializer { + + /** + * TODO Auto-generated attribute documentation + * + */ + private BookService bookService; + + /** + * TODO Auto-generated attribute documentation + * + */ + private ConversionService conversionService; + + /** + * TODO Auto-generated constructor documentation + * + * @param bookService + * @param conversionService + */ + @Autowired + public BookDeserializer(@Lazy BookService bookService, ConversionService conversionService) { + this.bookService = bookService; + this.conversionService = conversionService; + } +} diff --git a/roo/src/main/java/com/baeldung/web/BookDeserializer_Roo_EntityDeserializer.aj b/roo/src/main/java/com/baeldung/web/BookDeserializer_Roo_EntityDeserializer.aj new file mode 100644 index 0000000000..5ca42cfb5e --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BookDeserializer_Roo_EntityDeserializer.aj @@ -0,0 +1,78 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.domain.Book; +import com.baeldung.service.api.BookService; +import com.baeldung.web.BookDeserializer; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import io.springlets.web.NotFoundException; +import java.io.IOException; +import org.springframework.boot.jackson.JsonComponent; +import org.springframework.core.convert.ConversionService; + +privileged aspect BookDeserializer_Roo_EntityDeserializer { + + declare @type: BookDeserializer: @JsonComponent; + + /** + * TODO Auto-generated method documentation + * + * @return BookService + */ + public BookService BookDeserializer.getBookService() { + return bookService; + } + + /** + * TODO Auto-generated method documentation + * + * @param bookService + */ + public void BookDeserializer.setBookService(BookService bookService) { + this.bookService = bookService; + } + + /** + * TODO Auto-generated method documentation + * + * @return ConversionService + */ + public ConversionService BookDeserializer.getConversionService() { + return conversionService; + } + + /** + * TODO Auto-generated method documentation + * + * @param conversionService + */ + public void BookDeserializer.setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } + + /** + * TODO Auto-generated method documentation + * + * @param jsonParser + * @param context + * @param codec + * @param tree + * @return Book + * @throws IOException + */ + public Book BookDeserializer.deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException { + String idText = tree.asText(); + Long id = conversionService.convert(idText, Long.class); + Book book = bookService.findOne(id); + if (book == null) { + throw new NotFoundException("Book not found"); + } + return book; + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BookJsonMixin.java b/roo/src/main/java/com/baeldung/web/BookJsonMixin.java new file mode 100644 index 0000000000..1cde8f0e86 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BookJsonMixin.java @@ -0,0 +1,12 @@ +package com.baeldung.web; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.web.mvc.controller.annotations.config.RooJsonMixin; + +/** + * = BookJsonMixin + TODO Auto-generated class documentation + * + */ +@RooJsonMixin(entity = Book.class) +public abstract class BookJsonMixin { +} diff --git a/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController.java b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController.java new file mode 100644 index 0000000000..9b0179e234 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController.java @@ -0,0 +1,15 @@ +package com.baeldung.web; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.web.mvc.controller.annotations.ControllerType; +import org.springframework.roo.addon.web.mvc.controller.annotations.RooController; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooThymeleaf; + +/** + * = BooksCollectionThymeleafController + TODO Auto-generated class documentation + * + */ +@RooController(entity = Book.class, type = ControllerType.COLLECTION) +@RooThymeleaf +public class BooksCollectionThymeleafController { +} diff --git a/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Controller.aj b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Controller.aj new file mode 100644 index 0000000000..a87b76a745 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Controller.aj @@ -0,0 +1,35 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.service.api.BookService; +import com.baeldung.web.BooksCollectionThymeleafController; + +privileged aspect BooksCollectionThymeleafController_Roo_Controller { + + /** + * TODO Auto-generated attribute documentation + * + */ + private BookService BooksCollectionThymeleafController.bookService; + + /** + * TODO Auto-generated method documentation + * + * @return BookService + */ + public BookService BooksCollectionThymeleafController.getBookService() { + return bookService; + } + + /** + * TODO Auto-generated method documentation + * + * @param bookService + */ + public void BooksCollectionThymeleafController.setBookService(BookService bookService) { + this.bookService = bookService; + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Thymeleaf.aj b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Thymeleaf.aj new file mode 100644 index 0000000000..b0831730be --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafController_Roo_Thymeleaf.aj @@ -0,0 +1,470 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import ar.com.fdvs.dj.core.DynamicJasperHelper; +import ar.com.fdvs.dj.core.layout.ClassicLayoutManager; +import ar.com.fdvs.dj.domain.builders.ColumnBuilderException; +import ar.com.fdvs.dj.domain.builders.FastReportBuilder; +import com.baeldung.domain.Book; +import com.baeldung.service.api.BookService; +import com.baeldung.web.BooksCollectionThymeleafController; +import com.baeldung.web.BooksItemThymeleafController; +import com.baeldung.web.BooksItemThymeleafLinkFactory; +import com.baeldung.web.reports.ExportingErrorException; +import com.baeldung.web.reports.JasperReportsCsvExporter; +import com.baeldung.web.reports.JasperReportsExporter; +import com.baeldung.web.reports.JasperReportsPdfExporter; +import com.baeldung.web.reports.JasperReportsXlsExporter; +import io.springlets.data.domain.GlobalSearch; +import io.springlets.data.web.datatables.ConvertedDatatablesData; +import io.springlets.data.web.datatables.Datatables; +import io.springlets.data.web.datatables.DatatablesColumns; +import io.springlets.data.web.datatables.DatatablesPageable; +import io.springlets.data.web.select2.Select2DataSupport; +import io.springlets.data.web.select2.Select2DataWithConversion; +import io.springlets.web.mvc.util.ControllerMethodLinkBuilderFactory; +import io.springlets.web.mvc.util.MethodLinkBuilderFactory; +import java.io.IOException; +import java.util.Collection; +import java.util.Locale; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.util.UriComponents; + +privileged aspect BooksCollectionThymeleafController_Roo_Thymeleaf { + + declare @type: BooksCollectionThymeleafController: @Controller; + + declare @type: BooksCollectionThymeleafController: @RequestMapping(value = "/books", name = "BooksCollectionThymeleafController", produces = MediaType.TEXT_HTML_VALUE); + + /** + * TODO Auto-generated attribute documentation + * + */ + private MessageSource BooksCollectionThymeleafController.messageSource; + + /** + * TODO Auto-generated attribute documentation + * + */ + private MethodLinkBuilderFactory BooksCollectionThymeleafController.itemLink; + + /** + * TODO Auto-generated attribute documentation + * + */ + private ConversionService BooksCollectionThymeleafController.conversionService; + + /** + * TODO Auto-generated constructor documentation + * + * @param bookService + * @param conversionService + * @param messageSource + * @param linkBuilder + */ + @Autowired + public BooksCollectionThymeleafController.new(BookService bookService, ConversionService conversionService, MessageSource messageSource, ControllerMethodLinkBuilderFactory linkBuilder) { + setBookService(bookService); + setConversionService(conversionService); + setMessageSource(messageSource); + setItemLink(linkBuilder.of(BooksItemThymeleafController.class)); + } + + /** + * TODO Auto-generated method documentation + * + * @return MessageSource + */ + public MessageSource BooksCollectionThymeleafController.getMessageSource() { + return messageSource; + } + + /** + * TODO Auto-generated method documentation + * + * @param messageSource + */ + public void BooksCollectionThymeleafController.setMessageSource(MessageSource messageSource) { + this.messageSource = messageSource; + } + + /** + * TODO Auto-generated method documentation + * + * @return MethodLinkBuilderFactory + */ + public MethodLinkBuilderFactory BooksCollectionThymeleafController.getItemLink() { + return itemLink; + } + + /** + * TODO Auto-generated method documentation + * + * @param itemLink + */ + public void BooksCollectionThymeleafController.setItemLink(MethodLinkBuilderFactory itemLink) { + this.itemLink = itemLink; + } + + /** + * TODO Auto-generated method documentation + * + * @return ConversionService + */ + public ConversionService BooksCollectionThymeleafController.getConversionService() { + return conversionService; + } + + /** + * TODO Auto-generated method documentation + * + * @param conversionService + */ + public void BooksCollectionThymeleafController.setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } + + /** + * TODO Auto-generated method documentation + * + * @param model + * @return ModelAndView + */ + @GetMapping(name = "list") + public ModelAndView BooksCollectionThymeleafController.list(Model model) { + return new ModelAndView("/books/list"); + } + + /** + * TODO Auto-generated method documentation + * + * @param datatablesColumns + * @param search + * @param pageable + * @param draw + * @return ResponseEntity + */ + @GetMapping(produces = Datatables.MEDIA_TYPE, name = "datatables", value = "/dt") + @ResponseBody + public ResponseEntity> BooksCollectionThymeleafController.datatables(DatatablesColumns datatablesColumns, GlobalSearch search, DatatablesPageable pageable, @RequestParam("draw") Integer draw) { + Page books = getBookService().findAll(search, pageable); + long totalBooksCount = books.getTotalElements(); + if (search != null && StringUtils.isNotBlank(search.getText())) { + totalBooksCount = getBookService().count(); + } + ConvertedDatatablesData datatablesData = new ConvertedDatatablesData(books, totalBooksCount, draw, getConversionService(), datatablesColumns); + return ResponseEntity.ok(datatablesData); + } + + /** + * TODO Auto-generated method documentation + * + * @param search + * @param pageable + * @param locale + * @return ResponseEntity + */ + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE, name = "select2", value = "/s2") + @ResponseBody + public ResponseEntity> BooksCollectionThymeleafController.select2(GlobalSearch search, Pageable pageable, Locale locale) { + Page books = getBookService().findAll(search, pageable); + String idExpression = "#{id}"; + Select2DataSupport select2Data = new Select2DataWithConversion(books, idExpression, getConversionService()); + return ResponseEntity.ok(select2Data); + } + + /** + * TODO Auto-generated method documentation + * + * @param dataBinder + */ + @InitBinder("book") + public void BooksCollectionThymeleafController.initBookBinder(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields("id"); + } + + /** + * TODO Auto-generated method documentation + * + * @param model + */ + public void BooksCollectionThymeleafController.populateFormats(Model model) { + model.addAttribute("application_locale", LocaleContextHolder.getLocale().getLanguage()); + } + + /** + * TODO Auto-generated method documentation + * + * @param model + */ + public void BooksCollectionThymeleafController.populateForm(Model model) { + populateFormats(model); + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @param result + * @param model + * @return ModelAndView + */ + @PostMapping(name = "create") + public ModelAndView BooksCollectionThymeleafController.create(@Valid @ModelAttribute Book book, BindingResult result, Model model) { + if (result.hasErrors()) { + populateForm(model); + + return new ModelAndView("/books/create"); + } + Book newBook = getBookService().save(book); + UriComponents showURI = getItemLink().to(BooksItemThymeleafLinkFactory.SHOW).with("book", newBook.getId()).toUri(); + return new ModelAndView("redirect:" + showURI.toUriString()); + } + + /** + * TODO Auto-generated method documentation + * + * @param model + * @return ModelAndView + */ + @GetMapping(value = "/create-form", name = "createForm") + public ModelAndView BooksCollectionThymeleafController.createForm(Model model) { + populateForm(model); + + model.addAttribute("book", new Book()); + return new ModelAndView("books/create"); + } + + /** + * TODO Auto-generated method documentation + * + * @param ids + * @return ResponseEntity + */ + @DeleteMapping(value = "/batch/{ids}", name = "deleteBatch") + @ResponseBody + public ResponseEntity BooksCollectionThymeleafController.deleteBatch(@PathVariable("ids") Collection ids) { + + getBookService().delete(ids); + + return ResponseEntity.ok().build(); + } + + /** + * Method that obtains the filtered and ordered records using the Datatables information and + * export them to a new report file. (It ignores the current pagination). + * + * To generate the report file it uses the `DynamicJasper` library + * (http://dynamicjasper.com). This library allows developers to generate reports dynamically + * without use an specific template to each entity. + * + * To customize the appearance of ALL generated reports, you could customize the + * "export_default.jrxml" template located in "src/main/resources/templates/reports/". However, + * if you want to customize the appearance of this specific report, you could create a new + * ".jrxml" file and provide it to the library replacing the `builder.setTemplateFile();` + * operation used in this implementation. + * + * @param search GlobalSearch that contains the filter provided by the Datatables component. + * @param pageable Pageable that contains the Sort info provided by the Datatabes component. + * @param datatablesColumns Columns displayed in the Datatables component. + * @param response The HttpServletResponse. + * @param exporter An specific JasperReportsExporter to be used during export process. + * @param fileName The final filename to use. + * @param locale The current Locale in the view context. + */ + public void BooksCollectionThymeleafController.export(GlobalSearch search, @PageableDefault(size = 2147483647) Pageable pageable, String[] datatablesColumns, HttpServletResponse response, JasperReportsExporter exporter, String fileName, Locale locale) { + // Obtain the filtered and ordered elements + Page books = getBookService().findAll(search, pageable); + + // Prevent generation of reports with empty data + if (books == null || books.getContent().isEmpty()) { + return; + } + + // Creates a new ReportBuilder using DynamicJasper library + FastReportBuilder builder = new FastReportBuilder(); + + // IMPORTANT: By default, this application uses "export_default.jrxml" + // to generate all reports. If you want to customize this specific report, + // create a new ".jrxml" template and customize it. (Take in account the + // DynamicJasper restrictions: + // http://dynamicjasper.com/2010/10/06/how-to-use-custom-jrxml-templates/) + builder.setTemplateFile("templates/reports/export_default.jrxml"); + + // The generated report will display the same columns as the Datatables component. + // However, this is not mandatory. You could edit this code if you want to ignore + // the provided datatablesColumns + if (datatablesColumns != null) { + for (String column : datatablesColumns) { + // Delegates in addColumnToReportBuilder to include each datatables column + // to the report builder + addColumnToReportBuilder(column, builder, locale, fileName); + } + } + + // This property resizes the columns to use full width page. + // Set false value if you want to use the specific width of each column. + builder.setUseFullPageWidth(true); + + // Creates a new Jasper Reports Datasource using the obtained elements + JRDataSource ds = new JRBeanCollectionDataSource(books.getContent()); + + // Generates the JasperReport + JasperPrint jp; + try { + jp = DynamicJasperHelper.generateJasperPrint(builder.build(), new ClassicLayoutManager(), ds); + } + catch (JRException e) { + String errorMessage = getMessageSource().getMessage("error_exportingErrorException", + new Object[] {StringUtils.substringAfterLast(fileName, ".").toUpperCase()}, + String.format("Error while exporting data to StringUtils file", StringUtils. + substringAfterLast(fileName, ".").toUpperCase()), locale); + throw new ExportingErrorException(errorMessage); + } + + // Converts the JaspertReport element to a ByteArrayOutputStream and + // write it into the response stream using the provided JasperReportExporter + try { + exporter.export(jp, fileName, response); + } + catch (JRException e) { + String errorMessage = getMessageSource().getMessage("error_exportingErrorException", + new Object[] {StringUtils.substringAfterLast(fileName, ".").toUpperCase()}, + String.format("Error while exporting data to StringUtils file", StringUtils. + substringAfterLast(fileName, ".").toUpperCase()), locale); + throw new ExportingErrorException(errorMessage); + } + catch (IOException e) { + String errorMessage = getMessageSource().getMessage("error_exportingErrorException", + new Object[] {StringUtils.substringAfterLast(fileName, ".").toUpperCase()}, + String.format("Error while exporting data to StringUtils file", StringUtils. + substringAfterLast(fileName, ".").toUpperCase()), locale); + throw new ExportingErrorException(errorMessage); + } + } + + /** + * It delegates in the `export` method providing the necessary information + * to generate a CSV report. + * + * @param search The GlobalSearch that contains the filter provided by the Datatables component + * @param pageable The Pageable that contains the Sort info provided by the Datatabes component + * @param datatablesColumns The Columns displayed in the Datatables component + * @param response The HttpServletResponse + * @return ResponseEntity + */ + @GetMapping(name = "exportCsv", value = "/export/csv") + @ResponseBody + public ResponseEntity BooksCollectionThymeleafController.exportCsv(GlobalSearch search, @PageableDefault(size = 2147483647) Pageable pageable, @RequestParam("datatablesColumns") String[] datatablesColumns, HttpServletResponse response, Locale locale) { + export(search, pageable, datatablesColumns, response, new JasperReportsCsvExporter(), "books_report.csv", locale); + return ResponseEntity.ok().build(); + } + + /** + * It delegates in the `export` method providing the necessary information + * to generate a PDF report. + * + * @param search The GlobalSearch that contains the filter provided by the Datatables component + * @param pageable The Pageable that contains the Sort info provided by the Datatabes component + * @param datatablesColumns The Columns displayed in the Datatables component + * @param response The HttpServletResponse + * @return ResponseEntity + */ + @GetMapping(name = "exportPdf", value = "/export/pdf") + @ResponseBody + public ResponseEntity BooksCollectionThymeleafController.exportPdf(GlobalSearch search, @PageableDefault(size = 2147483647) Pageable pageable, @RequestParam("datatablesColumns") String[] datatablesColumns, HttpServletResponse response, Locale locale) { + export(search, pageable, datatablesColumns, response, new JasperReportsPdfExporter(), "books_report.pdf", locale); + return ResponseEntity.ok().build(); + } + + /** + * It delegates in the `export` method providing the necessary information + * to generate a XLS report. + * + * @param search The GlobalSearch that contains the filter provided by the Datatables component + * @param pageable The Pageable that contains the Sort info provided by the Datatabes component + * @param datatablesColumns The Columns displayed in the Datatables component + * @param response The HttpServletResponse + * @return ResponseEntity + */ + @GetMapping(name = "exportXls", value = "/export/xls") + @ResponseBody + public ResponseEntity BooksCollectionThymeleafController.exportXls(GlobalSearch search, @PageableDefault(size = 2147483647) Pageable pageable, @RequestParam("datatablesColumns") String[] datatablesColumns, HttpServletResponse response, Locale locale) { + export(search, pageable, datatablesColumns, response, new JasperReportsXlsExporter(), "books_report.xls", locale); + return ResponseEntity.ok().build(); + } + + /** + * This method contains all the entity fields that are able to be displayed in a + * report. The developer could add a new column to the report builder providing the + * field name and the builder where the new field will be added as column. + * + * @param columnName the field name to show as column + * @param builder The builder where the new field will be added as column. + */ + public void BooksCollectionThymeleafController.addColumnToReportBuilder(String columnName, FastReportBuilder builder, Locale locale, String fileName) { + try { + if (columnName.equals("id")) { + builder.addColumn(getMessageSource().getMessage("label_book_id", null, "Id", locale), "id", Long.class.getName(), 50); + } + else if (columnName.equals("version")) { + builder.addColumn(getMessageSource().getMessage("label_book_version", null, "Version", locale), "version", Integer.class.getName(), 100); + } + else if (columnName.equals("title")) { + builder.addColumn(getMessageSource().getMessage("label_book_title", null, "Title", locale), "title", String.class.getName(), 100); + } + else if (columnName.equals("author")) { + builder.addColumn(getMessageSource().getMessage("label_book_author", null, "Author", locale), "author", String.class.getName(), 100); + } + else if (columnName.equals("isbn")) { + builder.addColumn(getMessageSource().getMessage("label_book_isbn", null, "Isbn", locale), "isbn", String.class.getName(), 100); + } + } + catch (ColumnBuilderException e) { + String errorMessage = getMessageSource().getMessage("error_exportingErrorException", + new Object[] {StringUtils.substringAfterLast(fileName, ".").toUpperCase()}, + String.format("Error while exporting data to StringUtils file", StringUtils. + substringAfterLast(fileName, ".").toUpperCase()), locale); + throw new ExportingErrorException(errorMessage); + } + catch (ClassNotFoundException e) { + String errorMessage = getMessageSource().getMessage("error_exportingErrorException", + new Object[] {StringUtils.substringAfterLast(fileName, ".").toUpperCase()}, + String.format("Error while exporting data to StringUtils file", StringUtils. + substringAfterLast(fileName, ".").toUpperCase()), locale); + throw new ExportingErrorException(errorMessage); + } + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory.java b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory.java new file mode 100644 index 0000000000..413a5e64a0 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory.java @@ -0,0 +1,11 @@ +package com.baeldung.web; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooLinkFactory; + +/** + * = BooksCollectionThymeleafLinkFactory + TODO Auto-generated class documentation + * + */ +@RooLinkFactory(controller = BooksCollectionThymeleafController.class) +public class BooksCollectionThymeleafLinkFactory { +} diff --git a/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory_Roo_LinkFactory.aj b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory_Roo_LinkFactory.aj new file mode 100644 index 0000000000..e6df3efcb7 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksCollectionThymeleafLinkFactory_Roo_LinkFactory.aj @@ -0,0 +1,122 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.web.BooksCollectionThymeleafController; +import com.baeldung.web.BooksCollectionThymeleafLinkFactory; +import io.springlets.web.mvc.util.MethodLinkFactory; +import io.springlets.web.mvc.util.SpringletsMvcUriComponentsBuilder; +import java.util.Map; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; + +privileged aspect BooksCollectionThymeleafLinkFactory_Roo_LinkFactory { + + declare parents: BooksCollectionThymeleafLinkFactory implements MethodLinkFactory; + + declare @type: BooksCollectionThymeleafLinkFactory: @Component; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.LIST = "list"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.DATATABLES = "datatables"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.SELECT2 = "select2"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.CREATE = "create"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.CREATEFORM = "createForm"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.DELETEBATCH = "deleteBatch"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.EXPORTCSV = "exportCsv"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.EXPORTPDF = "exportPdf"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksCollectionThymeleafLinkFactory.EXPORTXLS = "exportXls"; + + /** + * TODO Auto-generated method documentation + * + * @return Class + */ + public Class BooksCollectionThymeleafLinkFactory.getControllerClass() { + return BooksCollectionThymeleafController.class; + } + + /** + * TODO Auto-generated method documentation + * + * @param methodName + * @param parameters + * @param pathVariables + * @return UriComponents + */ + public UriComponents BooksCollectionThymeleafLinkFactory.toUri(String methodName, Object[] parameters, Map pathVariables) { + if (methodName.equals(LIST)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).list(null)).buildAndExpand(pathVariables); + } + if (methodName.equals(DATATABLES)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).datatables(null, null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(SELECT2)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).select2(null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(CREATE)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).create(null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(CREATEFORM)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).createForm(null)).buildAndExpand(pathVariables); + } + if (methodName.equals(DELETEBATCH)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).deleteBatch(null)).buildAndExpand(pathVariables); + } + if (methodName.equals(EXPORTCSV)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).exportCsv(null, null, null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(EXPORTPDF)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).exportPdf(null, null, null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(EXPORTXLS)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).exportXls(null, null, null, null, null)).buildAndExpand(pathVariables); + } + throw new IllegalArgumentException("Invalid method name: " + methodName); + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController.java b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController.java new file mode 100644 index 0000000000..f16cb7be2d --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController.java @@ -0,0 +1,15 @@ +package com.baeldung.web; +import com.baeldung.domain.Book; +import org.springframework.roo.addon.web.mvc.controller.annotations.ControllerType; +import org.springframework.roo.addon.web.mvc.controller.annotations.RooController; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooThymeleaf; + +/** + * = BooksItemThymeleafController + TODO Auto-generated class documentation + * + */ +@RooController(entity = Book.class, type = ControllerType.ITEM) +@RooThymeleaf +public class BooksItemThymeleafController { +} diff --git a/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Controller.aj b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Controller.aj new file mode 100644 index 0000000000..c0a4ed46df --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Controller.aj @@ -0,0 +1,35 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.service.api.BookService; +import com.baeldung.web.BooksItemThymeleafController; + +privileged aspect BooksItemThymeleafController_Roo_Controller { + + /** + * TODO Auto-generated attribute documentation + * + */ + private BookService BooksItemThymeleafController.bookService; + + /** + * TODO Auto-generated method documentation + * + * @return BookService + */ + public BookService BooksItemThymeleafController.getBookService() { + return bookService; + } + + /** + * TODO Auto-generated method documentation + * + * @param bookService + */ + public void BooksItemThymeleafController.setBookService(BookService bookService) { + this.bookService = bookService; + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Thymeleaf.aj b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Thymeleaf.aj new file mode 100644 index 0000000000..502c30a81e --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafController_Roo_Thymeleaf.aj @@ -0,0 +1,251 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.domain.Book; +import com.baeldung.service.api.BookService; +import com.baeldung.web.BooksItemThymeleafController; +import com.baeldung.web.BooksItemThymeleafLinkFactory; +import io.springlets.web.NotFoundException; +import io.springlets.web.mvc.util.ControllerMethodLinkBuilderFactory; +import io.springlets.web.mvc.util.MethodLinkBuilderFactory; +import java.util.Locale; +import javax.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.util.UriComponents; + +privileged aspect BooksItemThymeleafController_Roo_Thymeleaf { + + declare @type: BooksItemThymeleafController: @Controller; + + declare @type: BooksItemThymeleafController: @RequestMapping(value = "/books/{book}", name = "BooksItemThymeleafController", produces = MediaType.TEXT_HTML_VALUE); + + /** + * TODO Auto-generated attribute documentation + * + */ + private MessageSource BooksItemThymeleafController.messageSource; + + /** + * TODO Auto-generated attribute documentation + * + */ + private MethodLinkBuilderFactory BooksItemThymeleafController.itemLink; + + /** + * TODO Auto-generated constructor documentation + * + * @param bookService + * @param messageSource + * @param linkBuilder + */ + @Autowired + public BooksItemThymeleafController.new(BookService bookService, MessageSource messageSource, ControllerMethodLinkBuilderFactory linkBuilder) { + setBookService(bookService); + setMessageSource(messageSource); + setItemLink(linkBuilder.of(BooksItemThymeleafController.class)); + } + + /** + * TODO Auto-generated method documentation + * + * @return MessageSource + */ + public MessageSource BooksItemThymeleafController.getMessageSource() { + return messageSource; + } + + /** + * TODO Auto-generated method documentation + * + * @param messageSource + */ + public void BooksItemThymeleafController.setMessageSource(MessageSource messageSource) { + this.messageSource = messageSource; + } + + /** + * TODO Auto-generated method documentation + * + * @return MethodLinkBuilderFactory + */ + public MethodLinkBuilderFactory BooksItemThymeleafController.getItemLink() { + return itemLink; + } + + /** + * TODO Auto-generated method documentation + * + * @param itemLink + */ + public void BooksItemThymeleafController.setItemLink(MethodLinkBuilderFactory itemLink) { + this.itemLink = itemLink; + } + + /** + * TODO Auto-generated method documentation + * + * @param id + * @param locale + * @param method + * @return Book + */ + @ModelAttribute + public Book BooksItemThymeleafController.getBook(@PathVariable("book") Long id, Locale locale, HttpMethod method) { + Book book = null; + if (HttpMethod.PUT.equals(method)) { + book = bookService.findOneForUpdate(id); + } else { + book = bookService.findOne(id); + } + + if (book == null) { + String message = messageSource.getMessage("error_NotFound", new Object[] {"Book", id}, "The record couldn't be found", locale); + throw new NotFoundException(message); + } + return book; + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @param model + * @return ModelAndView + */ + @GetMapping(name = "show") + public ModelAndView BooksItemThymeleafController.show(@ModelAttribute Book book, Model model) { + model.addAttribute("book", book); + return new ModelAndView("books/show"); + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @param model + * @return ModelAndView + */ + @GetMapping(value = "/inline", name = "showInline") + public ModelAndView BooksItemThymeleafController.showInline(@ModelAttribute Book book, Model model) { + model.addAttribute("book", book); + return new ModelAndView("books/showInline :: inline-content"); + } + + /** + * TODO Auto-generated method documentation + * + * @param dataBinder + */ + @InitBinder("book") + public void BooksItemThymeleafController.initBookBinder(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields("id"); + } + + /** + * TODO Auto-generated method documentation + * + * @param model + */ + public void BooksItemThymeleafController.populateFormats(Model model) { + model.addAttribute("application_locale", LocaleContextHolder.getLocale().getLanguage()); + } + + /** + * TODO Auto-generated method documentation + * + * @param model + */ + public void BooksItemThymeleafController.populateForm(Model model) { + populateFormats(model); + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @param model + * @return ModelAndView + */ + @GetMapping(value = "/edit-form", name = "editForm") + public ModelAndView BooksItemThymeleafController.editForm(@ModelAttribute Book book, Model model) { + populateForm(model); + + model.addAttribute("book", book); + return new ModelAndView("books/edit"); + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @param version + * @param concurrencyControl + * @param result + * @param model + * @return ModelAndView + */ + @PutMapping(name = "update") + public ModelAndView BooksItemThymeleafController.update(@Valid @ModelAttribute Book book, @RequestParam("version") Integer version, @RequestParam(value = "concurrency", required = false, defaultValue = "") String concurrencyControl, BindingResult result, Model model) { + // Check if provided form contain errors + if (result.hasErrors()) { + populateForm(model); + + return new ModelAndView("books/edit"); + } + // Concurrency control + Book existingBook = getBookService().findOne(book.getId()); + if(book.getVersion() != existingBook.getVersion() && StringUtils.isEmpty(concurrencyControl)){ + populateForm(model); + model.addAttribute("book", book); + model.addAttribute("concurrency", true); + return new ModelAndView("books/edit"); + } else if(book.getVersion() != existingBook.getVersion() && "discard".equals(concurrencyControl)){ + populateForm(model); + model.addAttribute("book", existingBook); + model.addAttribute("concurrency", false); + return new ModelAndView("books/edit"); + } else if(book.getVersion() != existingBook.getVersion() && "apply".equals(concurrencyControl)){ + // Update the version field to be able to override the existing values + book.setVersion(existingBook.getVersion()); + } + Book savedBook = getBookService().save(book); + UriComponents showURI = getItemLink().to(BooksItemThymeleafLinkFactory.SHOW).with("book", savedBook.getId()).toUri(); + return new ModelAndView("redirect:" + showURI.toUriString()); + } + + /** + * TODO Auto-generated method documentation + * + * @param book + * @return ResponseEntity + */ + @ResponseBody + @DeleteMapping(name = "delete") + public ResponseEntity BooksItemThymeleafController.delete(@ModelAttribute Book book) { + getBookService().delete(book); + return ResponseEntity.ok().build(); + } + +} diff --git a/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory.java b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory.java new file mode 100644 index 0000000000..5b69306868 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory.java @@ -0,0 +1,11 @@ +package com.baeldung.web; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooLinkFactory; + +/** + * = BooksItemThymeleafLinkFactory + TODO Auto-generated class documentation + * + */ +@RooLinkFactory(controller = BooksItemThymeleafController.class) +public class BooksItemThymeleafLinkFactory { +} diff --git a/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory_Roo_LinkFactory.aj b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory_Roo_LinkFactory.aj new file mode 100644 index 0000000000..fd68866587 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/BooksItemThymeleafLinkFactory_Roo_LinkFactory.aj @@ -0,0 +1,86 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.web.BooksItemThymeleafController; +import com.baeldung.web.BooksItemThymeleafLinkFactory; +import io.springlets.web.mvc.util.MethodLinkFactory; +import io.springlets.web.mvc.util.SpringletsMvcUriComponentsBuilder; +import java.util.Map; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; + +privileged aspect BooksItemThymeleafLinkFactory_Roo_LinkFactory { + + declare parents: BooksItemThymeleafLinkFactory implements MethodLinkFactory; + + declare @type: BooksItemThymeleafLinkFactory: @Component; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksItemThymeleafLinkFactory.SHOW = "show"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksItemThymeleafLinkFactory.SHOWINLINE = "showInline"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksItemThymeleafLinkFactory.EDITFORM = "editForm"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksItemThymeleafLinkFactory.UPDATE = "update"; + + /** + * TODO Auto-generated attribute documentation + * + */ + public static final String BooksItemThymeleafLinkFactory.DELETE = "delete"; + + /** + * TODO Auto-generated method documentation + * + * @return Class + */ + public Class BooksItemThymeleafLinkFactory.getControllerClass() { + return BooksItemThymeleafController.class; + } + + /** + * TODO Auto-generated method documentation + * + * @param methodName + * @param parameters + * @param pathVariables + * @return UriComponents + */ + public UriComponents BooksItemThymeleafLinkFactory.toUri(String methodName, Object[] parameters, Map pathVariables) { + if (methodName.equals(SHOW)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).show(null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(SHOWINLINE)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).showInline(null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(EDITFORM)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).editForm(null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(UPDATE)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).update(null, null, null, null, null)).buildAndExpand(pathVariables); + } + if (methodName.equals(DELETE)) { + return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).delete(null)).buildAndExpand(pathVariables); + } + throw new IllegalArgumentException("Invalid method name: " + methodName); + } + +} diff --git a/roo/src/main/java/com/baeldung/web/MainController.java b/roo/src/main/java/com/baeldung/web/MainController.java new file mode 100644 index 0000000000..bf2038b4a1 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/MainController.java @@ -0,0 +1,11 @@ +package com.baeldung.web; +import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooThymeleafMainController; + +/** + * = MainController + TODO Auto-generated class documentation + * + */ +@RooThymeleafMainController +public class MainController { +} diff --git a/roo/src/main/java/com/baeldung/web/MainController_Roo_Thymeleaf_MainController.aj b/roo/src/main/java/com/baeldung/web/MainController_Roo_Thymeleaf_MainController.aj new file mode 100644 index 0000000000..58f0466ed9 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/MainController_Roo_Thymeleaf_MainController.aj @@ -0,0 +1,59 @@ +// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. +// You may push code into the target .java compilation unit if you wish to edit any member(s). + +package com.baeldung.web; + +import com.baeldung.web.MainController; +import io.springlets.web.NotFoundException; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +privileged aspect MainController_Roo_Thymeleaf_MainController { + + declare @type: MainController: @Controller; + + /** + * TODO Auto-generated method documentation + * + * @param model + * @return String + */ + @GetMapping("/") + public String MainController.index(Model model) { + model.addAttribute("application_locale", LocaleContextHolder.getLocale().getLanguage()); + return "index"; + } + + /** + * TODO Auto-generated method documentation + * + * @param model + * @return String + */ + @GetMapping("/accessibility") + public String MainController.accessibility(Model model) { + model.addAttribute("application_locale", LocaleContextHolder.getLocale().getLanguage()); + return "accessibility"; + } + + /** + * TODO Auto-generated method documentation + * + * @param template + * @return String + */ + @RequestMapping(value = "/js/{template}.js", method = RequestMethod.GET) + public String MainController.javascriptTemplates(@PathVariable("template") String template) { + if (StringUtils.hasLength(template)) { + return template.concat(".js"); + } + throw new NotFoundException("File not found"); + } + +} diff --git a/roo/src/main/java/com/baeldung/web/reports/ExportingErrorException.java b/roo/src/main/java/com/baeldung/web/reports/ExportingErrorException.java new file mode 100644 index 0000000000..a8c2eca5cc --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/reports/ExportingErrorException.java @@ -0,0 +1,19 @@ +package com.baeldung.web.reports; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) +public class ExportingErrorException extends RuntimeException { + + private static final long serialVersionUID = 4075788919321977605L; + + public ExportingErrorException() { + super("Error while trying to export data to file."); + } + + public ExportingErrorException(String message) { + super(message); + } + +} diff --git a/roo/src/main/java/com/baeldung/web/reports/JasperReportsCsvExporter.java b/roo/src/main/java/com/baeldung/web/reports/JasperReportsCsvExporter.java new file mode 100644 index 0000000000..5ea23e16cc --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/reports/JasperReportsCsvExporter.java @@ -0,0 +1,71 @@ +package com.baeldung.web.reports; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRExporterParameter; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.export.JRCsvExporter; + +/** + * = JasperReportsCsvExporter + * + * A JasperReports exporter to export the report in CSV formats. This class + * implements the interface {@link JasperReportsExporter} + */ +public class JasperReportsCsvExporter implements JasperReportsExporter { + + /** + * Generates a ByteArrayOutputStream from the provided JasperReport using + * the {@link JRCsvExporter}. After that, the generated bytes array is + * written in the {@link HttpServletResponse} + * + * @param jp + * The generated JasperReport. + * @param fileName + * The fileName of the exported JasperReport + * @param response + * The HttpServletResponse where generated report has been + * written + * @throws JRException + * during JasperReport export. + * @throws IOException + * when writes the ByteArrayOutputStream into the + * HttpServletResponse + */ + @Override + public void export(JasperPrint jp, String fileName, HttpServletResponse response) throws JRException, IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Create a JRCsvExporter instance + JRCsvExporter exporter = new JRCsvExporter(); + + // Here we assign the parameters jp and baos to the exporter + exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); + exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos); + + // Retrieve the exported report in PDF format + exporter.exportReport(); + + // Specifies the response header + response.setHeader("Content-Disposition", "inline; filename=" + fileName); + + // Make sure to set the correct content type + // Each format has its own content type + response.setContentType("text/csv"); + response.setContentLength(baos.size()); + + // Retrieve the output stream + ServletOutputStream outputStream = response.getOutputStream(); + // Write to the output stream + baos.writeTo(outputStream); + // Flush the stream + outputStream.flush(); + + } +} \ No newline at end of file diff --git a/roo/src/main/java/com/baeldung/web/reports/JasperReportsExporter.java b/roo/src/main/java/com/baeldung/web/reports/JasperReportsExporter.java new file mode 100644 index 0000000000..32892df447 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/reports/JasperReportsExporter.java @@ -0,0 +1,41 @@ +package com.baeldung.web.reports; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.export.Exporter; + +/** + * = JasperReportsExporter + * + * This interface defines the operations for a JasperReport exporter. + * + * JasperReports library already provides an Exporter interface called + * {@link Exporter}. However, it doesn't provides an operation that writes the + * exported JasperReport into the {@link HttpServletResponse}. + */ +public interface JasperReportsExporter { + + /** + * This operation must be implemented by every JasperReport exporter to be + * able to write a generated report into a the {@link HttpServletResponse}}. + * + * @param jp + * The generated JasperReport. + * @param fileName + * The fileName of the exported JasperReport + * @param response + * The HttpServletResponse where generated report has been + * written + * @throws JRException + * during JasperReport export. + * @throws IOException + * when writes the ByteArrayOutputStream into the + * HttpServletResponse + */ + public void export(JasperPrint jp, String fileName, HttpServletResponse response) throws JRException, IOException; + +} \ No newline at end of file diff --git a/roo/src/main/java/com/baeldung/web/reports/JasperReportsPdfExporter.java b/roo/src/main/java/com/baeldung/web/reports/JasperReportsPdfExporter.java new file mode 100644 index 0000000000..ae1e2d8ee0 --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/reports/JasperReportsPdfExporter.java @@ -0,0 +1,71 @@ +package com.baeldung.web.reports; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRExporterParameter; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.export.JRPdfExporter; + +/** + * = JasperReportsPdfExporter + * + * A JasperReports exporter to export the report in PDF formats. This class + * implements the interface {@link JasperReportsExporter} + */ +public class JasperReportsPdfExporter implements JasperReportsExporter { + + /** + * Generates a ByteArrayOutputStream from the provided JasperReport using + * the {@link JRPdfExporter}. After that, the generated bytes array is + * written in the {@link HttpServletResponse} + * + * @param jp + * The generated JasperReport. + * @param fileName + * The fileName of the exported JasperReport + * @param response + * The HttpServletResponse where generated report has been + * written + * @throws JRException + * during JasperReport export. + * @throws IOException + * when writes the ByteArrayOutputStream into the + * HttpServletResponse + */ + @Override + public void export(JasperPrint jp, String fileName, HttpServletResponse response) throws JRException, IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Create a JRPdfExporter instance + JRPdfExporter exporter = new JRPdfExporter(); + + // Here we assign the parameters jp and baos to the exporter + exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); + exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos); + + // Retrieve the exported report in PDF format + exporter.exportReport(); + + // Specifies the response header + response.setHeader("Content-Disposition", "inline; filename=" + fileName); + + // Make sure to set the correct content type + // Each format has its own content type + response.setContentType("application/pdf"); + response.setContentLength(baos.size()); + + // Retrieve the output stream + ServletOutputStream outputStream = response.getOutputStream(); + // Write to the output stream + baos.writeTo(outputStream); + // Flush the stream + outputStream.flush(); + + } +} \ No newline at end of file diff --git a/roo/src/main/java/com/baeldung/web/reports/JasperReportsXlsExporter.java b/roo/src/main/java/com/baeldung/web/reports/JasperReportsXlsExporter.java new file mode 100644 index 0000000000..1855d1c93c --- /dev/null +++ b/roo/src/main/java/com/baeldung/web/reports/JasperReportsXlsExporter.java @@ -0,0 +1,77 @@ +package com.baeldung.web.reports; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRExporterParameter; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.export.JRXlsAbstractExporterParameter; +import net.sf.jasperreports.engine.export.JRXlsExporter; + +/** + * = JasperReportsXlsExporter + * + * A JasperReports exporter to export the report in XLS formats. This class + * implements the interface {@link JasperReportsExporter} + */ +public class JasperReportsXlsExporter implements JasperReportsExporter { + + /** + * Generates a ByteArrayOutputStream from the provided JasperReport using + * the {@link JRXlsExporter}. After that, the generated bytes array is + * written in the {@link HttpServletResponse} + * + * @param jp + * The generated JasperReport. + * @param fileName + * The fileName of the exported JasperReport + * @param response + * The HttpServletResponse where generated report has been + * written + * @throws JRException + * during JasperReport export. + * @throws IOException + * when writes the ByteArrayOutputStream into the + * HttpServletResponse + */ + @Override + public void export(JasperPrint jp, String fileName, HttpServletResponse response) throws JRException, IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // Create a JRXlsExporter instance + JRXlsExporter exporter = new JRXlsExporter(); + + // Here we assign the parameters jp and baos to the exporter + exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); + exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos); + + // Excel specific parameters + exporter.setParameter(JRXlsAbstractExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE); + exporter.setParameter(JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE); + exporter.setParameter(JRXlsAbstractExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE); + + // Retrieve the exported report in PDF format + exporter.exportReport(); + + // Specifies the response header + response.setHeader("Content-Disposition", "inline; filename=" + fileName); + + // Make sure to set the correct content type + // Each format has its own content type + response.setContentType("application/vnd.ms-excel"); + response.setContentLength(baos.size()); + + // Retrieve the output stream + ServletOutputStream outputStream = response.getOutputStream(); + // Write to the output stream + baos.writeTo(outputStream); + // Flush the stream + outputStream.flush(); + + } +} \ No newline at end of file diff --git a/roo/src/main/resources/application-dev.properties b/roo/src/main/resources/application-dev.properties new file mode 100644 index 0000000000..6723cabefa --- /dev/null +++ b/roo/src/main/resources/application-dev.properties @@ -0,0 +1,13 @@ +#Updated at Tue Apr 04 15:03:52 BST 2017 +#Tue Apr 04 15:03:52 BST 2017 +logging.file= +logging.level.com.baeldung=DEBUG +logging.level.com.querydsl.jpa.impl.JPAQuery=DEBUG +logging.level.org.hibernate.stat=DEBUG +logging.pattern.level=%5p - QP\:%X{querydsl.parameters} - +spring.jackson.serialization.indent-output=true +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.properties.hibernate.generate_statistics=true +spring.jpa.show-sql=true +spring.messages.cache-seconds=0 +spring.thymeleaf.mode=html diff --git a/roo/src/main/resources/application.properties b/roo/src/main/resources/application.properties new file mode 100644 index 0000000000..77eaa5f3fc --- /dev/null +++ b/roo/src/main/resources/application.properties @@ -0,0 +1,8 @@ +#Updated at Tue Apr 04 15:03:53 BST 2017 +#Tue Apr 04 15:03:53 BST 2017 +spring.datasource.driver-class-name=org.hsqldb.jdbcDriver +spring.datasource.url=jdbc\:hsqldb\:mem\:roo +spring.jpa.hibernate.naming.strategy=org.hibernate.cfg.ImprovedNamingStrategy +spring.messages.encoding=ISO-8859-1 +spring.messages.fallback-to-system-locale=false +spring.thymeleaf.mode=html diff --git a/roo/src/main/resources/banner.txt b/roo/src/main/resources/banner.txt new file mode 100644 index 0000000000..dd2932f7aa --- /dev/null +++ b/roo/src/main/resources/banner.txt @@ -0,0 +1,9 @@ +${AnsiColor.GREEN} _ + ___ _ __ _ __(_)_ __ __ _ _ __ ___ ___ +/ __| '_ \| '__| | '_ \ / _` | | '__/ _ \ / _ \ +\__ \ |_) | | | | | | | (_| | | | | (_) | (_) | +|___/ .__/|_| |_|_| |_|\__, | |_| \___/ \___/ + |_| |___/ + +${AnsiColor.BRIGHT_RED}Spring application made with Spring Roo 2.0 +Doubts? http://projects.spring.io/spring-roo/${AnsiColor.DEFAULT} diff --git a/roo/src/main/resources/messages.properties b/roo/src/main/resources/messages.properties new file mode 100644 index 0000000000..e61a266500 --- /dev/null +++ b/roo/src/main/resources/messages.properties @@ -0,0 +1,146 @@ +#Updated at Tue Apr 04 15:04:02 BST 2017 +#Tue Apr 04 15:04:02 BST 2017 +error_NotFound={0} with identifier ''{1}'' not found. +error_NotNull=Required. +error_Size=The field must be between {2} and {1} characters long. +error_datatables_loading=An error happened while loading list data +error_deleting_item=Error deleting selected item. +error_deleting_item_with_relationships=To delete the selected item, must delete its related elements before. +error_expired_session=Your session has been expired +error_export_empty=No data available to generate a report +error_invalid_date=Please enter a correct date/time +error_invalid_maskValue=Please enter a valid value +error_login=Invalid user and password +help_login=Enter your login and password +info_author=Spring Roo development team +info_closed_session=Log out correctly +info_delete_batch_confirm=Are you sure want to delete the selected items? +info_delete_item_confirm=Are you sure want to delete this item? +info_deleted_item_problem=Error deleting item +info_deleted_items_batch=Deleted items +info_deleted_items_number=Deleted items {0} +info_description=Spring Roo, a next-generation rapid application development tool for Java developers. With Roo you can easily build full Java applications in minutes. +info_error=An unexpected error has occurred +info_homepage_header=With Roo you can easily build full Java applications in minutes. +info_homepage_paragraph=Spring Roo is a next-generation rapid application development tool for Java developers.\nIt focuses on higher productivity, stock-standard Java APIs, high usability, avoiding engineering trade-offs and \nfacilitating easy Roo removal. +info_homepage_project=Hello, this is your home page. +info_homepage_thanks=Thanks for your interest in Spring Roo\! +info_no_deleted_item=No deleted item. +info_no_exist_item=Item doesn't exist. +info_security_login=You tried to access a restricted area of our application. By default, you can log in with +info_select_an_option=Select an option +info_spring_code=Known, modify and redistribute the source code. +info_spring_documentation=If you are looking for Reference Documentation you can get it here. +info_spring_site=All the info about Spring Roo development. +info_spring_support=If you have any question about the project, \nyou can check it. +info_twitter=As always, you can find us also on +label_accessibility=Accessibility +label_accessibility_alt=Level Double-A conformance, W3C WAI Web Content Accessibility Guidelines 2.0 +label_accessibility_lead=Accessibility policy application +label_accessibility_text=

Spring Roo Application is committed to ensuring the accessibility of its web content to people with disabilities. All of the content on our website will meet W3C WAI's Web Content Accessibility Guidelines 2.0, Level AA conformance. Any issues should be reported to springroo@disid.com.

The technologies that is depended to access the accessible content are HTML, CSS and Javascript.

+label_accessibility_title=Explanation of WCAG 2.0 Level Double-A Conformance +label_actions=Actions +label_add_entity=Add {0} +label_back=Back +label_book=Book +label_book_author=Author +label_book_id=Id +label_book_isbn=Isbn +label_book_iterable_to_add_cant_be_null_message=I T E R A B L E_ T O_ A D D_ C A N T_ B E_ N U L L_ M E S S A G E +label_book_iterable_to_remove_cant_be_null_message=I T E R A B L E_ T O_ R E M O V E_ C A N T_ B E_ N U L L_ M E S S A G E +label_book_plural=Books +label_book_title=Title +label_book_version=Version +label_change_password=Change password +label_close=Close +label_code=Code +label_concurrency_apply=Apply my changes anyway +label_concurrency_apply_info=(discard all the changes applied by the other users). +label_concurrency_discard=Discard all my changes and reload this record. +label_concurrency_title=Warning\! This record has been updated by another user. +label_contact=Contact +label_create=Create +label_create_entity=Create {0} +label_data_entity={0} data +label_datatables_add=Add +label_datatables_columns=Columns +label_datatables_decimal=. +label_datatables_delete=Delete +label_datatables_emptyTable=No data available in table +label_datatables_first=First +label_datatables_info=Showing _START_ to _END_ of _TOTAL_ entries +label_datatables_infoEmpty=Showing 0 to 0 of 0 entries +label_datatables_infoFiltered=(filtered from _MAX_ total entries) +label_datatables_infoPostFix= +label_datatables_last=Last +label_datatables_lengthMenu=Show _MENU_ entries +label_datatables_loadingRecords=Loading... +label_datatables_loading_error=An error happened while loading list data +label_datatables_next=Next +label_datatables_previous=Previous +label_datatables_processing=Processing... +label_datatables_search=Search\: +label_datatables_selectedRow=1 selected row +label_datatables_selectedRows=%d selected rows +label_datatables_showRows=Show %d rows +label_datatables_sortAscending=\: activate to sort column ascending +label_datatables_sortDescending=\: activate to sort column descending +label_datatables_thousands= +label_datatables_zeroRecords=No matching records found +label_delete=Delete +label_delete_entity=Delete {0} +label_documentation=Doc +label_edit=Edit +label_edit_entity=Edit {0} +label_edit_search=Edit search +label_entities_found={0} found +label_error=Error +label_errorpage=Error page +label_errorpage_header=\u00C2\u00A1Error\! +label_exit=Exit +label_export_empty_error=Empty report +label_filtered_by=Filtered By +label_goBack=Go Back +label_goEdit=Go to the editing page +label_goHome=Go to homepage +label_gotoGithub=Go to Spring Roo page in GitHub +label_gotoLanguage=Display website in +label_gotowebsite=Go to Spring Roo website +label_help=Help +label_inputmask_groupSeparator=, +label_inputmask_prefix=$ +label_inputmask_radixPoint=. +label_inputmask_suffix= +label_last_access=Last Access {0} +label_list_entity=List {0} +label_list_of_entity=List of {0} +label_login=Login +label_login_password=Password +label_login_username=User +label_logout=Log out +label_menu_entry={0} +label_message=Message +label_not_filtered=Not Filtered +label_owasp_alt=Application developed and tested with OWASP +label_owasp_title=Application developed and tested with OWASP - Web Application Security Project +label_profile=Admin Profile +label_projectpage=Project Page +label_requiredfield=Required field +label_reset=Cancel +label_save=Save +label_search=Search +label_search_entity={0} searcher +label_show=Show +label_show_entity={0} card +label_spring_documentation=Spring Roo reference documentation +label_spring_site=Spring Roo project site +label_spring_sourcecode=Spring Roo source code +label_spring_support=Spring Roo Stackoverflow support +label_submit=Accept +label_support=Support +label_tools=Tools +label_user=User +language_label=Languages +language_label_en=English +language_label_es=Spanish +welcome_label=Welcome diff --git a/roo/src/main/resources/static/public/css/springroo.css b/roo/src/main/resources/static/public/css/springroo.css new file mode 100644 index 0000000000..2db8914ff1 --- /dev/null +++ b/roo/src/main/resources/static/public/css/springroo.css @@ -0,0 +1,475 @@ +/* CSS Theme Roo */ + +body { + background-color: #f1f1f1; + color: rgba(13,13,13,.65); + line-height: 1.8; + letter-spacing: .01em; +} +img {border: 0; max-width: 100%; outline: none;} +a{ + color: #6db33f; + transition: color 150ms ease; + } +a:focus, a:hover{ + outline: none; + color: #3f6824; + } +.content a:hover {text-decoration: underline} +.content a.btn-action:hover, +.content .paginate_button a:hover, +.content a.btn:hover {text-decoration: none;} + +.clearfix {clear: both;} + +/*--NAVBAR-------------*/ + +.navbar-header .organization-logo {vertical-align: middle; padding: 0.2em 1em;} +.navbar-header .application-name { color: #34302d;} +.navbar-header .application-name strong {} +.navbar-default .navbar-header .application-name a {text-decoration: none;} +.navbar-inverse .navbar-header .application-name a {color: #fff; text-decoration: none;} +.navbar-header .application-name small {} + +.dropdown-menu > li button.btn-link { + display: block; + padding: 3px 20px; + white-space: nowrap; + color: #333; + width: 100%; + text-align: left; +} +.dropdown-menu > li button.btn-link:hover, +.dropdown-menu > li button.btn-link:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active button.btn-link, +.dropdown-menu > .active button.btn-link:hover, +.dropdown-menu > .active button.btn-link:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} + +/*--FOOTER-------------*/ + +footer { padding: 1em 0 3em; text-align: center;} +footer p{font-size: 0.875em;} +footer a:hover, footer a:focus{text-decoration: none;} + + + +/*--HEADINGS-------------*/ + +.content h4,h5,h6 {color: #34302d;} + +/*--CONTENT-------------*/ + +/* second container */ +.content { + clear: both; + min-height: 26.3em; + display: block; + padding: 1em; + background: #fff; + box-shadow: 0 0 0 0,0 6px 12px rgba(34,34,34,.1); +} +.content > .panel{ +/* margin: 1em; */ +} + +/*--SHOW-------------*/ + +.content ul.list-unstyled li{ + margin: 0.25em 0; +} +.content ul.list-unstyled li{ + padding: 0.25em 0; +} +.content ul.list-unstyled li strong{ + min-width: 15%; + display: inline-block; + } +.content ul.list-unstyled li span{ + display: inline-block; + padding-left: 1em; +} +.content [id$="FieldSet"] h2{ + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: inherit; + border-bottom: 1px solid #f1f1f1; +} +dd, dt { + margin: 0px 5px 5px 0px; +} + +/*--ALERTS-------------*/ + +.alert blockquote{ + margin: 0; + font-size: inherit; +} +.alert-info blockquote { + border-left-color: #31708f; +} +/*--FORMS-------------*/ + +legend{ + border-bottom: 1px solid #f1f1f1; +} +.form-horizontal .form-group input[type="radio"], +.form-horizontal .form-group input[type="checkbox"] { + margin-left: 0; +} + +/*--TABLES-------------*/ + +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc { + background-image: none; +} + +/** toolbars datatables **/ +div.dataTables_wrapper div.dataTables_paginate, +div.dataTables_wrapper div.dataTables_info{ + padding: 0; +} + +div.dataTables_wrapper div.dataTables_filter, +div.dataTables_wrapper div.dt-buttons.btn-group{ + padding: 1em 0; +} +.pagination{ + text-transform: none; +} +.dataTables_wrapper .dataTables_paginate .paginate_button{ + padding: 0; +} +.dataTables_wrapper .dataTables_paginate .paginate_button:hover { + background: none; +} +/** btn datatables **/ +table a.btn-action { + text-decoration: none; + color: #3e3f3a; +} +table .btn-action + .btn-action { + margin: 0 0 0 0.35em; +} +table a.btn-action:hover, +table a.btn-action:focus, +table a.btn-action:active { + color: #79a736; +} +table.dataTable.no-footer { + border-bottom: 1px solid #dfd7ca; +} + +div.dataTables_wrapper div.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 200px; + margin-left: -100px; + margin-top: 16px; + padding: 0.5em 0; + height: 30px; + overflow: hidden; + border-radius: 4px; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; + font-size: 12px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} +/*--BTN-------------*/ + +.btn-action:before { + font-family: 'FontAwesome'; + padding: 0 0.3em 0 0; +} +.btn-action.delete:before { + content:"\f014"; + } +.btn-action.edit:before, +.btn-action.modify:before { + content:"\f040"; + } +.btn-action.accept:before { + content:"\f00c"; + } +.btn-action.add:before { + content:"\f067"; + } +.btn-action.showInfo:before { + content:"\f06e"; +} +.alert a.btn{ + color: #555555; + text-decoration: none; +} + +/*-------------------INDEX-------------------*/ + +body.home .content{ + background: none; + padding: 0; + box-shadow: none; +} +body.home .box-center{ + padding: 1em 2em; + background: #fff; + box-shadow: 0 0 0 0,0 6px 12px rgba(34,34,34,.1); +} +body.home .navbar { margin-bottom: 0px;} + +/*--HEADER-------------*/ +.jumbotron { + min-height: 6.5em; + text-align: center; + vertical-align: middle; + margin-bottom: 2em; + background-color: #316128; + background-image: linear-gradient(120deg, #316128, #254211); + border-bottom: 1px solid #969595; + border: none; +} +.jumbotron.bg-banner { + min-height: 20em; + color: #fff; + text-align: center; + padding: 3em; + background-image: url(../img/geo.png); + background-repeat: no-repeat; + background-position: 50% 20%; + -webkit-background-size: cover; + -moz-background-size: cover; + -o-background-size: cover; + background-size: cover; +} +.jumbotron .project-name{ + color: #fff; + text-align: center; + font-size: 4em; +} +.jumbotron .project-tagline { + color: #fff; + margin-bottom: 2rem; + font-weight: normal; + opacity: 0.7; +} + +/*--SOCIAL LINKS-------------*/ + +.social-links a{ + color: #999; + text-decoration: none; + font-size: 1.5em; + margin: 0 0.15em; +} + +/*--BLOCKS----------------*/ + +.blocks { margin-top: 2em;} +.block-item { + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + position: relative; + margin-bottom: 30px; +} +.block-item .doc { + padding: 15px; + float: left; + font-size: 4em; +} +.block-item a{ + color: #fff; + cursor: pointer; +} +.block-item .text { + overflow: hidden; + color: rgba(255, 255, 255, 0.9); + padding: 16px 12px; +} +.block-item .text > h2 { + margin: 0; + line-height: 100%; + font-size: 22px; + font-weight: 300; + color: #fff; +} +.block-item .text > small { + margin-bottom: 2px; + display: block; +} +.block-item .text > p, +.block-item .text > h2 { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.block-item > .clearfix, +.block-item > .dl-horizontal dd, +.block-item > .container, +.block-item > .container-fluid, +.block-item > .row, +.block-item > .form-horizontal .form-group, +.block-item > .btn-toolbar, +.block-item > .btn-group-vertical > .btn-group, +.block-item > .nav, +.block-item > .navbar, +.block-item > .navbar-header, +.block-item > .navbar-collapse, +.block-item > .pager, +.block-item > .panel-body, +.block-item > .modal-header, +.block-item > .modal-footer { + position: relative; + z-index: 1; +} +.block-item:before { + -webkit-transition: width; + -o-transition: width; + transition: width; + -webkit-transition-duration: 500ms; + transition-duration: 500ms; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + backface-visibility: hidden; + content: ""; + width: 83px; + height: 100%; + background: rgba(0, 0, 0, 0.1); + position: absolute; + left: 0; + top: 0; +} +.block-item:hover .text {color: #fff !important;} +.block-item:hover:before { width: 100%;} + +/* + * Material Background Colors + */ + +.bgm-teal { background-color: #009688 !important;} +.bgm-red { background-color: #f44336 !important;} +.bgm-amber { background-color: #ffc107 !important;} +.bgm-bluegray {background-color: #607d8b !important;} + + +/* SANDSTONE THEME CUSTOM +-----------------------------------------------------------------------------*/ + +/*-- NAVBAR -------------*/ + +.navbar-default .navbar-header .application-name a {color: #fff; text-decoration: none;} + +.dropdown-menu > li button.btn-link { + clear: both; + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; + color: #98978b; +} +.dropdown-menu > li button.btn-link:hover, +.dropdown-menu > li button.btn-link:focus { + color: #98978b; + background-color: #f8f5f0; +} +.dropdown-menu > .active button.btn-link, +.dropdown-menu > .active button.btn-link:hover, +.dropdown-menu > .active button.btn-link:focus { + color: #98978b; + background-color: #f8f5f0; +} + +/*-- SELECT2 -------------*/ + +.select2-container--bootstrap .select2-selection{ + height: 46px; + padding: 12px 16px; + font-size: 14px; + line-height: 1.42857143; + color: #3e3f3a; + background-color: #ffffff; + background-image: none; + border: 1px solid #dfd7ca; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.select2-container--bootstrap .select2-selection--multiple { + padding: 6px; +} +.select2-container--bootstrap .select2-selection--multiple .select2-selection__arrow, +.select2-container--bootstrap .select2-selection--multiple .select2-selection__placeholder, +.select2-container--bootstrap .select2-selection--single .select2-selection__arrow, +.select2-container--bootstrap .select2-selection--single .select2-selection__placeholder{ + color: #dfd7ca; + padding: 0; +} +.select2-container--bootstrap .select2-selection--multiple .select2-selection__arrow b, +.select2-container--bootstrap .select2-selection--single .select2-selection__arrow b { + border-color: #dfd7ca transparent transparent transparent; +} +/* align options in left */ +.select2-container--bootstrap .select2-selection--multiple .select2-selection__rendered{ + padding-right: 0.5em !important; +} +.select2-container--bootstrap .select2-selection--multiple .select2-selection__clear { + margin-right: 0 !important; +} + +/* MEDIA QUERIES +-------------------------------------------------------------------------------*/ + +@media print { + body {background: #fff;} + .content .main {width: 98%;} +} + +@media (max-width: 768px) { + .jumbotron .project-name{font-size: 3em;} + /* navbar fixes */ + .navbar-nav#entitiesMenuEntries { + max-width: 410px; + } +} + +@media (max-width: 992px){ + .navbar-nav.upper-nav > li > a {padding: 15px 5px} +} + +@media (min-width: 1020px){ + /* navbar fixes */ + .navbar-nav#entitiesMenuEntries { + max-width: 370px; + } +} + +@media (min-width: 1100px){ + /* navbar fixes */ + .navbar-nav#entitiesMenuEntries { + max-width: 50%; + } +} diff --git a/roo/src/main/resources/static/public/css/theme.css b/roo/src/main/resources/static/public/css/theme.css new file mode 100644 index 0000000000..02722dd20c --- /dev/null +++ b/roo/src/main/resources/static/public/css/theme.css @@ -0,0 +1,6914 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto:400,500"); +/*! + * bootswatch v3.3.6 + * Homepage: http://bootswatch.com + * Copyright 2012-2015 Thomas Park + * Licensed under MIT + * Based on Bootstrap + * Sandstone theme +*/ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +/*mark { + background: #ff0; + color: #000; +}*/ +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + color: inherit; + font: inherit; + margin: 0; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + text-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +/* @font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} */ +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\002a"; +} +.glyphicon-plus:before { + content: "\002b"; +} +.glyphicon-euro:before, +.glyphicon-eur:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.glyphicon-cd:before { + content: "\e201"; +} +.glyphicon-save-file:before { + content: "\e202"; +} +.glyphicon-open-file:before { + content: "\e203"; +} +.glyphicon-level-up:before { + content: "\e204"; +} +.glyphicon-copy:before { + content: "\e205"; +} +.glyphicon-paste:before { + content: "\e206"; +} +.glyphicon-alert:before { + content: "\e209"; +} +.glyphicon-equalizer:before { + content: "\e210"; +} +.glyphicon-king:before { + content: "\e211"; +} +.glyphicon-queen:before { + content: "\e212"; +} +.glyphicon-pawn:before { + content: "\e213"; +} +.glyphicon-bishop:before { + content: "\e214"; +} +.glyphicon-knight:before { + content: "\e215"; +} +.glyphicon-baby-formula:before { + content: "\e216"; +} +.glyphicon-tent:before { + content: "\26fa"; +} +.glyphicon-blackboard:before { + content: "\e218"; +} +.glyphicon-bed:before { + content: "\e219"; +} +.glyphicon-apple:before { + content: "\f8ff"; +} +.glyphicon-erase:before { + content: "\e221"; +} +.glyphicon-hourglass:before { + content: "\231b"; +} +.glyphicon-lamp:before { + content: "\e223"; +} +.glyphicon-duplicate:before { + content: "\e224"; +} +.glyphicon-piggy-bank:before { + content: "\e225"; +} +.glyphicon-scissors:before { + content: "\e226"; +} +.glyphicon-bitcoin:before { + content: "\e227"; +} +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} +.glyphicon-yen:before { + content: "\00a5"; +} +.glyphicon-jpy:before { + content: "\00a5"; +} +.glyphicon-ruble:before { + content: "\20bd"; +} +.glyphicon-rub:before { + content: "\20bd"; +} +.glyphicon-scale:before { + content: "\e230"; +} +.glyphicon-ice-lolly:before { + content: "\e231"; +} +.glyphicon-ice-lolly-tasted:before { + content: "\e232"; +} +.glyphicon-education:before { + content: "\e233"; +} +.glyphicon-option-horizontal:before { + content: "\e234"; +} +.glyphicon-option-vertical:before { + content: "\e235"; +} +.glyphicon-menu-hamburger:before { + content: "\e236"; +} +.glyphicon-modal-window:before { + content: "\e237"; +} +.glyphicon-oil:before { + content: "\e238"; +} +.glyphicon-grain:before { + content: "\e239"; +} +.glyphicon-sunglasses:before { + content: "\e240"; +} +.glyphicon-text-size:before { + content: "\e241"; +} +.glyphicon-text-color:before { + content: "\e242"; +} +.glyphicon-text-background:before { + content: "\e243"; +} +.glyphicon-object-align-top:before { + content: "\e244"; +} +.glyphicon-object-align-bottom:before { + content: "\e245"; +} +.glyphicon-object-align-horizontal:before { + content: "\e246"; +} +.glyphicon-object-align-left:before { + content: "\e247"; +} +.glyphicon-object-align-vertical:before { + content: "\e248"; +} +.glyphicon-object-align-right:before { + content: "\e249"; +} +.glyphicon-triangle-right:before { + content: "\e250"; +} +.glyphicon-triangle-left:before { + content: "\e251"; +} +.glyphicon-triangle-bottom:before { + content: "\e252"; +} +.glyphicon-triangle-top:before { + content: "\e253"; +} +.glyphicon-console:before { + content: "\e254"; +} +.glyphicon-superscript:before { + content: "\e255"; +} +.glyphicon-subscript:before { + content: "\e256"; +} +.glyphicon-menu-left:before { + content: "\e257"; +} +.glyphicon-menu-right:before { + content: "\e258"; +} +.glyphicon-menu-down:before { + content: "\e259"; +} +.glyphicon-menu-up:before { + content: "\e260"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.42857143; + color: #3e3f3a; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #93c54b; + text-decoration: none; +} +a:hover, +a:focus { + color: #79a736; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + padding: 4px; + line-height: 1.42857143; + background-color: #f8f5f0; + border: 1px solid #dfd7ca; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #f8f5f0; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +[role="button"] { + cursor: pointer; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 400; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #98978b; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +/*mark, +.mark { + background-color: #fcf8e3; + padding: .2em; +}*/ +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #98978b; +} +.text-primary { + color: #325d88; +} +a.text-primary:hover, +a.text-primary:focus { + color: #244363; +} +.text-success { + color: #93c54b; +} +a.text-success:hover, +a.text-success:focus { + color: #79a736; +} +.text-info { + color: #29abe0; +} +a.text-info:hover, +a.text-info:focus { + color: #1b8dbb; +} +.text-warning { + color: #f47c3c; +} +a.text-warning:hover, +a.text-warning:focus { + color: #ef5c0e; +} +.text-danger { + color: #d9534f; +} +a.text-danger:hover, +a.text-danger:focus { + color: #c9302c; +} +.bg-primary { + color: #fff; + background-color: #325d88; +} +a.bg-primary:hover, +a.bg-primary:focus { + background-color: #244363; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover, +a.bg-success:focus { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover, +a.bg-info:focus { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover, +a.bg-warning:focus { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover, +a.bg-danger:focus { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #f8f5f0; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; + margin-left: -5px; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +dl { + margin-top: 0; + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #98978b; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #dfd7ca; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #3e3f3a; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #dfd7ca; + border-left: 0; + text-align: right; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #ffffff; + background-color: #333333; + border-radius: 3px; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + -webkit-box-shadow: none; + box-shadow: none; +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + word-break: break-all; + word-wrap: break-word; + color: #8e8c84; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #98978b; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #dfd7ca; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dfd7ca; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #dfd7ca; +} +.table .table { + background-color: #ffffff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #dfd7ca; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dfd7ca; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #f8f5f0; +} +.table-hover > tbody > tr:hover { + background-color: #f8f5f0; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f8f5f0; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #f0e9df; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table-responsive { + overflow-x: auto; + min-height: 0.01%; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dfd7ca; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + padding: 0; + margin: 0; + border: 0; + min-width: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: inherit; + border: 0; + border-bottom: 1px solid transparent; +} +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 13px; + font-size: 14px; + line-height: 1.42857143; + color: #3e3f3a; +} +.form-control { + display: block; + width: 100%; + height: 46px; + padding: 12px 16px; + font-size: 14px; + line-height: 1.42857143; + color: #3e3f3a; + background-color: #ffffff; + background-image: none; + border: 1px solid #dfd7ca; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +/* .form-control:focus { + border-color: transparent; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6); +} */ +.form-control::-moz-placeholder { + color: #dfd7ca; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #dfd7ca; +} +.form-control::-webkit-input-placeholder { + color: #dfd7ca; +} +.form-control::-ms-expand { + border: 0; + background-color: transparent; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #f8f5f0; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"].form-control, + input[type="time"].form-control, + input[type="datetime-local"].form-control, + input[type="month"].form-control { + line-height: 46px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .input-group-sm input[type="date"], + .input-group-sm input[type="time"], + .input-group-sm input[type="datetime-local"], + .input-group-sm input[type="month"] { + line-height: 30px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .input-group-lg input[type="date"], + .input-group-lg input[type="time"], + .input-group-lg input[type="datetime-local"], + .input-group-lg input[type="month"] { + line-height: 66px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 13px; + padding-bottom: 13px; + margin-bottom: 0; + min-height: 34px; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.form-group-sm select.form-control { + height: 30px; + line-height: 30px; +} +.form-group-sm textarea.form-control, +.form-group-sm select[multiple].form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 30px; + min-height: 32px; + padding: 6px 10px; + font-size: 12px; + line-height: 1.5; +} +.input-lg { + height: 66px; + padding: 20px 30px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-lg { + height: 66px; + line-height: 66px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 66px; + padding: 20px 30px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +.form-group-lg select.form-control { + height: 66px; + line-height: 66px; +} +.form-group-lg textarea.form-control, +.form-group-lg select[multiple].form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 66px; + min-height: 38px; + padding: 21px 30px; + font-size: 18px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 57.5px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 46px; + height: 46px; + line-height: 46px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback, +.input-group-lg + .form-control-feedback, +.form-group-lg .form-control + .form-control-feedback { + width: 66px; + height: 66px; + line-height: 66px; +} +.input-sm + .form-control-feedback, +.input-group-sm + .form-control-feedback, +.form-group-sm .form-control + .form-control-feedback { + width: 30px; + height: 30px; + line-height: 30px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #93c54b; +} +.has-success .form-control { + border-color: #93c54b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #79a736; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c1de98; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c1de98; +} +.has-success .input-group-addon { + color: #93c54b; + border-color: #93c54b; + background-color: #dff0d8; +} +.has-success .form-control-feedback { + color: #93c54b; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #f47c3c; +} +.has-warning .form-control { + border-color: #f47c3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #ef5c0e; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f9bd9d; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f9bd9d; +} +.has-warning .input-group-addon { + color: #f47c3c; + border-color: #f47c3c; + background-color: #fcf8e3; +} +.has-warning .form-control-feedback { + color: #f47c3c; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #d9534f; +} +.has-error .form-control { + border-color: #d9534f; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #c9302c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #eba5a3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #eba5a3; +} +.has-error .input-group-addon { + color: #d9534f; + border-color: #d9534f; + background-color: #f2dede; +} +.has-error .form-control-feedback { + color: #d9534f; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #7f8177; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 13px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 33px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 13px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 21px; + font-size: 18px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + font-size: 12px; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 12px 16px; + font-size: 14px; + line-height: 1.42857143; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #ffffff; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +a.btn.disabled, +fieldset[disabled] a.btn { + pointer-events: none; +} +.btn-default { + color: #ffffff; + background-color: #3e3f3a; + border-color: transparent; +} +.btn-default:focus, +.btn-default.focus { + color: #ffffff; + background-color: #242422; + border-color: rgba(0, 0, 0, 0); +} +.btn-default:hover { + color: #ffffff; + background-color: #242422; + border-color: rgba(0, 0, 0, 0); +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #ffffff; + background-color: #242422; + border-color: rgba(0, 0, 0, 0); +} +.btn-default:active:hover, +.btn-default.active:hover, +.open > .dropdown-toggle.btn-default:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.open > .dropdown-toggle.btn-default:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn-default.focus { + color: #ffffff; + background-color: #121210; + border-color: rgba(0, 0, 0, 0); +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + background-color: #3e3f3a; + border-color: transparent; +} +.btn-default .badge { + color: #3e3f3a; + background-color: #ffffff; +} +.btn-primary { + color: #ffffff; + background-color: #325d88; + border-color: transparent; +} +.btn-primary:focus, +.btn-primary.focus { + color: #ffffff; + background-color: #244363; + border-color: rgba(0, 0, 0, 0); +} +.btn-primary:hover { + color: #ffffff; + background-color: #244363; + border-color: rgba(0, 0, 0, 0); +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #244363; + border-color: rgba(0, 0, 0, 0); +} +.btn-primary:active:hover, +.btn-primary.active:hover, +.open > .dropdown-toggle.btn-primary:hover, +.btn-primary:active:focus, +.btn-primary.active:focus, +.open > .dropdown-toggle.btn-primary:focus, +.btn-primary:active.focus, +.btn-primary.active.focus, +.open > .dropdown-toggle.btn-primary.focus { + color: #ffffff; + background-color: #1b3249; + border-color: rgba(0, 0, 0, 0); +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus { + background-color: #325d88; + border-color: transparent; +} +.btn-primary .badge { + color: #325d88; + background-color: #ffffff; +} +.btn-success { + color: #ffffff; + background-color: #93c54b; + border-color: transparent; +} +.btn-success:focus, +.btn-success.focus { + color: #ffffff; + background-color: #79a736; + border-color: rgba(0, 0, 0, 0); +} +.btn-success:hover { + color: #ffffff; + background-color: #79a736; + border-color: rgba(0, 0, 0, 0); +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #79a736; + border-color: rgba(0, 0, 0, 0); +} +.btn-success:active:hover, +.btn-success.active:hover, +.open > .dropdown-toggle.btn-success:hover, +.btn-success:active:focus, +.btn-success.active:focus, +.open > .dropdown-toggle.btn-success:focus, +.btn-success:active.focus, +.btn-success.active.focus, +.open > .dropdown-toggle.btn-success.focus { + color: #ffffff; + background-color: #658c2d; + border-color: rgba(0, 0, 0, 0); +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus { + background-color: #93c54b; + border-color: transparent; +} +.btn-success .badge { + color: #93c54b; + background-color: #ffffff; +} +.btn-info { + color: #ffffff; + background-color: #29abe0; + border-color: transparent; +} +.btn-info:focus, +.btn-info.focus { + color: #ffffff; + background-color: #1b8dbb; + border-color: rgba(0, 0, 0, 0); +} +.btn-info:hover { + color: #ffffff; + background-color: #1b8dbb; + border-color: rgba(0, 0, 0, 0); +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #1b8dbb; + border-color: rgba(0, 0, 0, 0); +} +.btn-info:active:hover, +.btn-info.active:hover, +.open > .dropdown-toggle.btn-info:hover, +.btn-info:active:focus, +.btn-info.active:focus, +.open > .dropdown-toggle.btn-info:focus, +.btn-info:active.focus, +.btn-info.active.focus, +.open > .dropdown-toggle.btn-info.focus { + color: #ffffff; + background-color: #17759c; + border-color: rgba(0, 0, 0, 0); +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus { + background-color: #29abe0; + border-color: transparent; +} +.btn-info .badge { + color: #29abe0; + background-color: #ffffff; +} +.btn-warning { + color: #ffffff; + background-color: #f47c3c; + border-color: transparent; +} +.btn-warning:focus, +.btn-warning.focus { + color: #ffffff; + background-color: #ef5c0e; + border-color: rgba(0, 0, 0, 0); +} +.btn-warning:hover { + color: #ffffff; + background-color: #ef5c0e; + border-color: rgba(0, 0, 0, 0); +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ef5c0e; + border-color: rgba(0, 0, 0, 0); +} +.btn-warning:active:hover, +.btn-warning.active:hover, +.open > .dropdown-toggle.btn-warning:hover, +.btn-warning:active:focus, +.btn-warning.active:focus, +.open > .dropdown-toggle.btn-warning:focus, +.btn-warning:active.focus, +.btn-warning.active.focus, +.open > .dropdown-toggle.btn-warning.focus { + color: #ffffff; + background-color: #ce4f0c; + border-color: rgba(0, 0, 0, 0); +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus { + background-color: #f47c3c; + border-color: transparent; +} +.btn-warning .badge { + color: #f47c3c; + background-color: #ffffff; +} +.btn-danger { + color: #ffffff; + background-color: #d9534f; + border-color: transparent; +} +.btn-danger:focus, +.btn-danger.focus { + color: #ffffff; + background-color: #c9302c; + border-color: rgba(0, 0, 0, 0); +} +.btn-danger:hover { + color: #ffffff; + background-color: #c9302c; + border-color: rgba(0, 0, 0, 0); +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #c9302c; + border-color: rgba(0, 0, 0, 0); +} +.btn-danger:active:hover, +.btn-danger.active:hover, +.open > .dropdown-toggle.btn-danger:hover, +.btn-danger:active:focus, +.btn-danger.active:focus, +.open > .dropdown-toggle.btn-danger:focus, +.btn-danger:active.focus, +.btn-danger.active.focus, +.open > .dropdown-toggle.btn-danger.focus { + color: #ffffff; + background-color: #ac2925; + border-color: rgba(0, 0, 0, 0); +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus { + background-color: #d9534f; + border-color: transparent; +} +.btn-danger .badge { + color: #d9534f; + background-color: #ffffff; +} +.btn-link { + color: #93c54b; + font-weight: normal; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link.active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #79a736; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #dfd7ca; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 20px 30px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-property: height, visibility; + -o-transition-property: height, visibility; + transition-property: height, visibility; + -webkit-transition-duration: 0.35s; + -o-transition-duration: 0.35s; + transition-duration: 0.35s; + -webkit-transition-timing-function: ease; + -o-transition-timing-function: ease; + transition-timing-function: ease; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-top: 4px solid \9; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + text-align: left; + background-color: #ffffff; + border: 1px solid #dfd7ca; + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #f8f5f0; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #98978b; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #98978b; + background-color: #f8f5f0; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #98978b; + text-decoration: none; + outline: 0; + background-color: #f8f5f0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #dfd7ca; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #dfd7ca; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px dashed; + border-bottom: 4px solid \9; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn, +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-right-radius: 0; + border-top-left-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + float: none; + display: table-cell; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group .form-control:focus { + z-index: 3; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 66px; + padding: 20px 30px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 66px; + line-height: 66px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 12px 16px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #3e3f3a; + text-align: center; + background-color: #f8f5f0; + border: 1px solid #dfd7ca; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 20px 30px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + z-index: 2; + margin-left: -1px; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #f8f5f0; +} +.nav > li.disabled > a { + color: #dfd7ca; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #dfd7ca; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #f8f5f0; + border-color: #93c54b; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dfd7ca; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #dfd7ca #dfd7ca #dfd7ca; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #98978b; + background-color: #ffffff; + border: 1px solid #dfd7ca; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dfd7ca; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dfd7ca; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #98978b; + background-color: #f8f5f0; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dfd7ca; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dfd7ca; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar { + position: relative; + min-height: 60px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 20px 15px; + font-size: 18px; + line-height: 20px; + height: 60px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 13px; + margin-bottom: 13px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 10px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 20px; + padding-bottom: 20px; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 7px; + margin-bottom: 7px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 7px; + margin-bottom: 7px; +} +.navbar-btn.btn-sm { + margin-top: 15px; + margin-bottom: 15px; +} +.navbar-btn.btn-xs { + margin-top: 19px; + margin-bottom: 19px; +} +.navbar-text { + margin-top: 20px; + margin-bottom: 20px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #3e3f3a; + border-color: #3e3f3a; +} +.navbar-default .navbar-brand { + color: #ffffff; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #8e8c84; +} +.navbar-default .navbar-nav > li > a { + color: #98978b; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #393a35; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: transparent; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #393a35; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #98978b; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #3e3f3a; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #393a35; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #98978b; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #393a35; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #98978b; +} +.navbar-default .navbar-link:hover { + color: #ffffff; +} +.navbar-default .btn-link { + color: #98978b; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #ffffff; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #cccccc; +} +.navbar-inverse { + background-color: #93c54b; + border-color: #93c54b; +} +.navbar-inverse .navbar-brand { + color: #ffffff; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #dfd7ca; +} +.navbar-inverse .navbar-nav > li > a { + color: #6b9430; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #89be3d; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: transparent; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #89be3d; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #6b9430; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #81b33a; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #89be3d; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #93c54b; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #93c54b; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #6b9430; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #89be3d; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #6b9430; +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.navbar-inverse .btn-link { + color: #6b9430; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #ffffff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #444444; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f8f5f0; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #dfd7ca; +} +.breadcrumb > .active { + color: #98978b; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 12px 16px; + line-height: 1.42857143; + text-decoration: none; + color: #98978b; + background-color: #f8f5f0; + border: 1px solid #dfd7ca; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + z-index: 2; + color: #8e8c84; + background-color: #dfd7ca; + border-color: #dfd7ca; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 3; + color: #8e8c84; + background-color: #dfd7ca; + border-color: #dfd7ca; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #dfd7ca; + background-color: #f8f5f0; + border-color: #dfd7ca; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 20px 30px; + font-size: 18px; + line-height: 1.3333333; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 6px; + border-top-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #f8f5f0; + border: 1px solid #dfd7ca; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #dfd7ca; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #dfd7ca; + background-color: #f8f5f0; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #3e3f3a; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #242422; +} +.label-primary { + background-color: #325d88; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #244363; +} +.label-success { + background-color: #93c54b; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #79a736; +} +.label-info { + background-color: #29abe0; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #1b8dbb; +} +.label-warning { + background-color: #f47c3c; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ef5c0e; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: normal; + color: #ffffff; + line-height: 1; + vertical-align: middle; + white-space: nowrap; + text-align: center; + background-color: #93c54b; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #ffffff; + background-color: #93c54b; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding-top: 30px; + padding-bottom: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #f8f5f0; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #e8decd; +} +.container .jumbotron, +.container-fluid .jumbotron { + border-radius: 6px; + padding-left: 15px; + padding-right: 15px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron, + .container-fluid .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.42857143; + background-color: #f8f5f0; + border: 1px solid #dfd7ca; + border-radius: 4px; + -webkit-transition: border 0.2s ease-in-out; + -o-transition: border 0.2s ease-in-out; + transition: border 0.2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #93c54b; +} +.thumbnail .caption { + padding: 9px; + color: #3e3f3a; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #93c54b; + border-color: transparent; + color: #ffffff; +} +.alert-success hr { + border-top-color: rgba(0, 0, 0, 0); +} +.alert-success .alert-link { + color: #e6e6e6; +} +.alert-info { + background-color: #29abe0; + border-color: transparent; + color: #ffffff; +} +.alert-info hr { + border-top-color: rgba(0, 0, 0, 0); +} +.alert-info .alert-link { + color: #e6e6e6; +} +.alert-warning { + background-color: #f47c3c; + border-color: transparent; + color: #ffffff; +} +.alert-warning hr { + border-top-color: rgba(0, 0, 0, 0); +} +.alert-warning .alert-link { + color: #e6e6e6; +} +.alert-danger { + background-color: #d9534f; + border-color: transparent; + color: #ffffff; +} +.alert-danger hr { + border-top-color: rgba(0, 0, 0, 0); +} +.alert-danger .alert-link { + color: #e6e6e6; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #ffffff; + text-align: center; + background-color: #325d88; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #93c54b; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #29abe0; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f47c3c; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media, +.media-body { + zoom: 1; + overflow: hidden; +} +.media-body { + width: 10000px; +} +.media-object { + display: block; +} +.media-object.img-thumbnail { + max-width: none; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dfd7ca; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +a.list-group-item, +button.list-group-item { + color: #3e3f3a; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: inherit; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + text-decoration: none; + color: #3e3f3a; + background-color: #f8f5f0; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #f8f5f0; + color: #dfd7ca; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #dfd7ca; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #3e3f3a; + background-color: #f8f5f0; + border-color: #dfd7ca; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #3e3f3a; +} +.list-group-item-success { + color: #93c54b; + background-color: #dff0d8; +} +a.list-group-item-success, +button.list-group-item-success { + color: #93c54b; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #93c54b; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #93c54b; + border-color: #93c54b; +} +.list-group-item-info { + color: #29abe0; + background-color: #d9edf7; +} +a.list-group-item-info, +button.list-group-item-info { + color: #29abe0; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #29abe0; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #29abe0; + border-color: #29abe0; +} +.list-group-item-warning { + color: #f47c3c; + background-color: #fcf8e3; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #f47c3c; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #f47c3c; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #f47c3c; + border-color: #f47c3c; +} +.list-group-item-danger { + color: #d9534f; + background-color: #f2dede; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #d9534f; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #d9534f; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #d9534f; + border-color: #d9534f; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f8f5f0; + border-top: 1px solid #dfd7ca; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #dfd7ca; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #dfd7ca; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dfd7ca; +} +.panel-default { + border-color: #dfd7ca; +} +.panel-default > .panel-heading { + color: #3e3f3a; + background-color: #f8f5f0; + border-color: #dfd7ca; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #dfd7ca; +} +.panel-default > .panel-heading .badge { + color: #f8f5f0; + background-color: #3e3f3a; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #dfd7ca; +} +.panel-primary { + border-color: #325d88; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #325d88; + border-color: #325d88; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #325d88; +} +.panel-primary > .panel-heading .badge { + color: #325d88; + background-color: #ffffff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #325d88; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #93c54b; + background-color: #93c54b; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #93c54b; + background-color: #93c54b; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #29abe0; + background-color: #29abe0; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #29abe0; + background-color: #29abe0; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #f47c3c; + background-color: #f47c3c; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #f47c3c; + background-color: #f47c3c; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #d9534f; + background-color: #d9534f; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #d9534f; + background-color: #d9534f; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + left: 0; + bottom: 0; + height: 100%; + width: 100%; + border: 0; +} +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} +.embed-responsive-4by3 { + padding-bottom: 75%; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f8f5f0; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000000; + text-shadow: 0 0 0 transparent; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #f8f5f0; + border-radius: 6px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + -webkit-background-clip: padding-box; + background-clip: padding-box; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #f8f5f0; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #f8f5f0; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 12px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 1; + filter: alpha(opacity=100); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + background-color: #3e3f3a; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #3e3f3a; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + right: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #3e3f3a; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #3e3f3a; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #3e3f3a; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #3e3f3a; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #3e3f3a; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #3e3f3a; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #3e3f3a; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 14px; + background-color: #ffffff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #dfd7ca; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 14px; + background-color: #f8f5f0; + border-bottom: 1px solid #f0e9df; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top > .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #b9a78a; + border-top-color: #dfd7ca; + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #b9a78a; + border-right-color: #dfd7ca; +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #b9a78a; + border-bottom-color: #dfd7ca; + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #b9a78a; + border-left-color: #dfd7ca; +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform 0.6s ease-in-out; + -o-transition: -o-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000px; + perspective: 1000px; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + left: 0; + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + left: 0; + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + left: 0; + } +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + background-color: rgba(0, 0, 0, 0); +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001))); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5))); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control:hover, +.carousel-control:focus { + outline: 0; + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + margin-top: -10px; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + line-height: 1; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -10px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -10px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -10px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-header:before, +.modal-header:after, +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-header:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +.sandstone { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.navbar .nav > li > a { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.navbar-form input, +.navbar-form .form-control { + border: none; +} +.btn { + border: none; + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.btn:hover { + border-color: transparent; +} +.btn-lg { + line-height: 26px; +} +.btn-default:hover { + background-color: #393a35; +} +input, +.form-control { + -webkit-box-shadow: none; + box-shadow: none; +} +/* input:focus, +.form-control:focus { + border-color: #dfd7ca; + -webkit-box-shadow: none; + box-shadow: none; +} */ +.nav { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + border-color: #dfd7ca; +} +.nav-tabs > li > a { + background-color: #f8f5f0; + border-color: #dfd7ca; + color: #98978b; +} +.nav-tabs > li.disabled > a:hover { + background-color: #f8f5f0; +} +.nav-pills a { + color: #98978b; +} +.nav-pills li > a { + border: 1px solid transparent; +} +.nav-pills li.active > a, +.nav-pills li > a:hover { + border-color: #dfd7ca; +} +.nav-pills li.disabled > a { + border-color: transparent; +} +.breadcrumb { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; + border: 1px solid #dfd7ca; +} +.breadcrumb a { + color: #98978b; +} +.pagination { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.pager { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.pager li > a { + color: #98978b; +} +.dropdown-menu > li > a { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.alert a, +.alert .alert-link { + color: #fff; +} +.tooltip { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.progress { + border-radius: 10px; + background-color: #dfd7ca; + -webkit-box-shadow: none; + box-shadow: none; +} +.progress-bar { + -webkit-box-shadow: none; + box-shadow: none; +} +.list-group-item { + padding: 16px 24px; +} +.well { + -webkit-box-shadow: none; + box-shadow: none; +} +.panel { + -webkit-box-shadow: none; + box-shadow: none; +} +.panel .panel-heading, +.panel .panel-title { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; + color: #fff; +} +.panel .panel-footer { + font-size: 11px; + line-height: 22px; + font-weight: 500; + text-transform: uppercase; +} +.panel-default .panel-heading, +.panel-default .panel-title, +.panel-default .panel-footer { + color: #98978b; +} diff --git a/roo/src/main/resources/static/public/fonts/fontawesome-webfont.eot b/roo/src/main/resources/static/public/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..99e847f985b54ecc5e8dd5003d4775cd387b799c GIT binary patch literal 75220 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/roo/src/main/resources/static/public/fonts/fontawesome-webfont.ttf b/roo/src/main/resources/static/public/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f471fde429ccdfbf6c62b9746d0c75faaade7f2f GIT binary patch literal 150920 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

jH0rRyLL+1|R$y$3@bdgc?;t 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ℨ{dsBK*`T4-6b-D1rq7 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

cl(Ou6^Utmxy^`$=v=$va*K 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 Ucf|P*8a#-I?padb-XkLVUsriYi2wiq literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/fonts/fontawesome-webfont.woff2 b/roo/src/main/resources/static/public/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..aaed3de59c52ca76abc62d509676652b40d55ae4 GIT binary patch literal 70728 zcmZTvQ*0o96Rd4sZQJgzwr#t;+D@%BshQfk+O}<8ZC|bL|NiaEX5TiGY%-ad^--1K zgn)#AfPlo2gFySQLn(VgKw_Ujz(B_SH~n7$85u2QVnT8_Gl(cCOa!EuT7;+_GDu!1 zYUor?2co$O zx?u~bIp2~^e*gT041n9Dh8^(y4abh7#obh;P*UYU1B+Ny2vQ6($Lh6aD0R*RY9v(o zDjn|~bB8kTanuE)at-(9>n2Y7kz)`9u{BYmARsB`qr9(|()e9i$C{M8EK|bxqAQc! z^@CByesMX$g*f$QdC9fe?)XU^I8>lvR^vU&^iP{R%t75&5Af{cbKo@K2n>>}%fC>% znNdiDLc~B^{V|d3Dr4kxJ|apU}?r6QxiWg0&CZz6&}qMTU){;Pb=iR3Kxx zDetyix`XmzV<$@7zu)|&sCyZ><$ODyp(w^5kzpqt5EFWT>+AdW{+*%tQ~lCDAAJHP zJ5Rnnh#=3xy!Fud{oAw{h_}m}TcyaP42O@?iuOkG<6ZoMFM!?=K`QL_QsG+dF#15FbDR`m3E5c(I|!k>JmptE&{3 zR+QjtPTREQQoCLu%u%TM!xxcrNvI20|E>tg6)8&#Qb%5L7>sAiZYRpYDl(4#EKW5gK*Nr%5-U zM~FdVDhdME*S}w&zIG)EiYg#TK1zLkrBzy{Zx z)fVLN5Zj-nC%Ub=`o7?^{#8a|U#`1)&|t(VaIult;1K=o=TuoY4QVv?#>5ik(gGZu4y zY8x=juZL`T?$vsl%d>BTuhPCxvmZGt6@V{`A2kcNq5r*E4HB4;PO~#6@Mv?&k;Xdv zvCu^e?$dC;Q)|>4C!c;)S3X%7;<*$q^Gv6lXH9EtJ{3)`erzTJ_Mi)1AOMV*0+iS! zE&T>1!v-AvCZ4sjn1VaKoV%6sl3n(gJ!!eXH_JICJ^tjgR7tu2;>8VHdTH7YvL zXOH=8qx*VKs?wqIj2WT1r$med!Xa}0-1JoIH)`GB(sx`ZdJ1nWjU&lXGpnF;i>a=` zlMP0)N>w}w*5NJs#m}I^*&Y16GXj4OSdT$`Uh3!aOxfWRd@lZrJz{^SQk) zN+49hneG@zHm-^}2>CI9gz~k2TE~Sj5jG`&ygSjtMaY`1>zpA4R45lPi^n_lSe_>)s)>1zF6OJ@${Yn&; zPm*npQ`?sPHpTESEX`DH`>hZwBu2)QO`_icU7g#-qW}63_{59A3fR110O|&J5QB%8b@5Ogdsxa`J z-Pt-9Cm7hpJ<5+(jL_v6Q_4w9x3%RF=Ul4;7ZyZkI)8(iCkf>hOmn@JfP96iGB-{w zfqi1a=f->~r)Qi3Z$4h6+b`s7uU;eWQS0v-@z_y{Djy{q z%Y;g1lo$kly0@i4ZEWMRd4xE(C98__Gr<69glKbB^cH@SMIeqGQR3~f#9w#s@5^N*fY_EfBz((u4gS4)$QH-^ryrvlCbv-x*#g)J?QjTX35&B z-g&C)hMC;<_Xh9X=MiTIDiLTGs1g_tZ)~o1Vp2y{w)JMIzb2c+*zv?If4raBqu{$k z33wfeiYDqJ6$gCiknm2Iu_jHgk)Rkr`=HU!Z9TyHc>EUL zdI_fVrbRRFBH7=MK#NE_$GyeCWmfPSAa?8ONN4A@0xqo*YdJ=p6=3IYFsSB229TI< zW(1Y{?GH~5>62rO+!PUp>wBVFfauph&#*40?Y-sb=rLfYxO3Hcvz|#Ot^rbf5IlFD zX1YoQ0<+d;WJ5VPRx2>-<5%L(4`i}4Z}YzPvohS$;&488e|ODmW3*4Br-z5byMf8i#@WCgEm7M<2kdr-SZNah z6H@+urb3}{bs827J;MMGI*?#eaMV`6yGYR{M9$U_2X${DJ2wS zgA!EJ(lr{P^X6Ns*9$(0qVZB3YfVB!3_26}LeXdPJ}iX*A6x_e(4P zZiIgJjlAPrM@=&^EH-JHM2+=qADcQ775cGxn{ak|c(i{t^ZGEM8M143}Q+Hs{7xtB9KJY^|so3n|V#I^U|mN7lL0yOfc& z*=%jMV(UcaKy&$4R`>JiW@k1ofI5ARk(xS@GxD`+M_2_X*1b*LawTJgS2+%#OG)4= zWR82O*MK#-E9(7EqAY@id|B*@8eWz4G_F^VG$VX7SC)Q&omT)Yl#omN>Mq?@nS
j0s;6+k3VBhH195iM@+jSx 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 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.svg b/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000000..94fb5490a2 --- /dev/null +++ b/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.ttf b/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06e2a16b443c2d296f7fdf95eea5c7c20e81a6a7 GIT binary patch literal 45404 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 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff b/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..dda02ad5372b7771616f56ddc04bf58f8ab9bbaa GIT binary patch literal 23424 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⋘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 r*WvQ}vj00xp)KfYD-wz$vNU#5o&H6t8)Z(KX literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff2 b/roo/src/main/resources/static/public/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..ad69b8d4c10507b7b80d8894bf97822aa81bccfc GIT binary patch literal 18028 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 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/img/es.png b/roo/src/main/resources/static/public/img/es.png new file mode 100644 index 0000000000000000000000000000000000000000..c2de2d7111e3cb59cf6511dd2ab045e824bdb43e GIT binary patch literal 469 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 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/img/geo.png b/roo/src/main/resources/static/public/img/geo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4995b6f56d45bad081f089ac6e166c9f7e2a4fc GIT binary patch literal 142350 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 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/img/logo.png b/roo/src/main/resources/static/public/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e23f915763c67d9101f70d4883325da7911e4f5d GIT binary patch literal 1761 zcmV<71|Io|P)n6U0*s&eQdzqQ94?9ln zWq0FC3^qslG`n-t|9o@K|NPI<$T8D0f{oFzO2h^f3*2O$bH4*Nvj|Mf*>wTD4TKw` z;eRG#1I}XF`K>@X@Br}h#TGUXP5S+UX&Lt~Ch+&>{D0N7jNdGH@TO&K1}bx|`+z^2 zma$`@@B9w{k>?&i@R(^C2TjXpSg7F50^ld?d%zjfGX7v%#_ELtUU(r>0sI@d89)k9 z3W`*z9$-JPyQ8f$_DzE~fW5$Sr65w{(mN~|&lLL*C?E-(2lfH)0H1WUb@qPU;O_?B z07{jDhDw*_u*>`1Izr6qy`#VoFbs@%$BV!@pbI$UIX%+R)|r|uc-=eJ0;K>#!0AEB zT{qbbH#!_Vqv6+P{N6He6|-}|yQXFQ1K8Km)|sAh!g`XRc8X?@@YWF@_iaq`omvOm zotLlP0Q>^j4ea$ocgAd^0pTep1$=o~@a`8r9^8_lzG7Yl<`Upepu@C`=uE*&pyDfv zO~QvKbizzR>2 zr>+HF1GWJh^Kz+xlr8w^q)ua{Vr8|<`g)hvW`~N9OUeM zLDGhiq~OA3N#BUz!lWhh>MQDKa)M9nx)fRZ{qnNl^q?emOy~5V#5c8`{K!+a1;J~H*nnz`hF1dj zPuGFVDM44i#^HoUc}P)Prci+EvC)*pq~)D+J%^U~;f4yu#zu#XBS>75xfHrH5gQmP z+QT+R!&P3=2B(`wFJ5aNS!q z2?vhry!NTDptSHw7#x$NovbsruCQrZ=I-UC!|CXzo@YJn^L#8GX(~27*bZE|?vpJE zo#!>qOijiq*GH0&ak5wID;1C2p4t$LM}8fPM_Pd`KppT#EFM{!7ko!s=Lz7K^C4Kq z(t`dGk+-!>+K|kE6l$_Vn}BD%F6{}A^EU!Ji_9wRJ;2j*jsJYfoN@C%>k0-M|U&e-hXli$}ImXj))e>jk(^0*?WK>(XxucyLRa_4Urx-4`NDl`nnl z=Z9-E)Rd_YbjiPfkAP33n|g*Po{z;NRY26Myq^Ql6|E(vW!wq;(Hncr$*M~g54WVK zTB5E3mjZUS``J+MfFN`7qS)}K?Ok8YWyC!>2ljj3J_ID@vg<8P8EQ)ZAJZ8J{`!HR z+A^0Ty^@y?`j36s-cb!dQNOEjIa%o(w(k0>PD%=@^&vB#==qr*hnirOO+D0Es;g=G> z20;WBb!BRGUAf&dp5e#CgsRpEZ@d8EX#nZMXjc(x62$Os0rX00000NkvXXu0mjf DKx9>r literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/img/owasp_logo.png b/roo/src/main/resources/static/public/img/owasp_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8c820aa076ce15ef4908439a9d5c478c7641f2db GIT binary patch literal 4271 zcmV;g5K!-lP)QM#DFdeRffQ#1Y{F}Xbeyx z2uW#(P-y9zOhg`{8^A5s$Er~ti&ecNFG*t&HqHf-2{N%^xV<0o{(KrAIp%g{W}zt6VGeS{DY zLSR`YY|DmiTd-{#gb=u{3(xgH90G?pujGQ@1MAnXFYoB;!s<0^CJ9djT2T~aSq4ql zFZMidm+QKD$8k_96`-30t!?w*IBhUY7sz68SwOMyI&@uP+0qZ9xw!?lZ6~U#KC*W0 z+S?x3vIX~S+&D>jEa*|lx~|{pxb8!~?}KxS`li{KKI2l<2h(7h8Z1MDWoj@C9h#~l zNr6J~1P&hF17Z*2sw=L5rYeXS`}M|q?s?xN;xV8{!-b}6ce<|kkmERzF>t{}|BR-F z4!E`khZrE10b-jV#Dr}dFijn*svwRN6pIm#^$p+`zj+kPmo7qMLp>N}f7<$`FU?wh z*@v*}rJqfL1^`vl7kZxivg0_2Qw57IUWa_nN6xW8Yy*UtaEJ-VG2u8iT*rh>3>bz6 zC_r7EgIBxz(9=7Fpa0@pcvnXqrnI(#bG~bPSJ#z)?;foN`2dEg>%Q+j=lee5M8SfK z*CFtHIJODX)L@u8EK`SR>aZ*Wgy=AB9j<4?aV>bR4PDnU^V}Ak+u4eb{Nt@S_(l;! zg#v`&%Wu5##>Hn^z^wDnpK!jbtLxOYX<4VPr%j(Wq5fCC@|9E9*I&PKLYDdp}EP$(j_V%YiVv?*wWI{K4nUqcGlFhN{;Jx_xJbz2*B$A zkP8Am2y&aJv`w+6w6!Tyr%uK6>C>U8YIgGNw|kEtKmK0;y49xUM#r-3FFKBchUPiQ z`7>Y|8gx~Gs;MJzfiwe>Bt+gq@viYj3uDo_EAkG+E&)q}_dCs=&_Yp$=;JD6DJ&Mj_=IA%vTzDF8TzWgR27eWz_(MMB844sl*^ zJuhX9eQ{`Tu)1p1O`f02LDO|KG&b}&4*8~S+wBe^dmYF5C2^b*rS#K`(${YN)Tb5! zKoA7F@B4QULKYK;w7IU^X4!TdrO`CT*k>7M`>$NS{3_kHoh7DeqFgFs&U>!Kob&22 zI8;I4n{ZtVo@c@L9n?3tXm0XBh>2oLCX-|rCeh2Q@6xA%?XwB`1-YgdF}`1Ca&`&iR|eE<6c zj_ZOD=d`WqdH#f3mU9jv1cVR(fP6mx#UKc#Xv(aP}fcl=zg zImiWVhG8yw>7|!`HCFfTyY5<74XcBdYULIHFXw{*uIs9VkZn&t{mj$j@BNXFeE8+z zO63{Vw(Tp3Z9_FIm{uze9v*_@xo}+@jLMP0QLQjgD&V>{+Nah*Qx(WKL7HYrk`%+k z0*787ME_f52$4X>DKu3_XXpD+EEXZ8SONeG7cK+%bx8G@!bsfiZ>&JQ_l9a9IN#1i>`Vb9*LwDWy`0MNt$|N`u-<38v

$gPEr9D*Q+d_I`)g;%T9Z$y;3x@}pP8m5Wn)_FjdLBoK^&R8>yNi%K#}7gjE4#0A~_X#*lG> zrlz^*>p28FBf$mpE+l*Q?4bZqmkZ$Ma`1gG8^5@(e(h_x_L^%HN-1bmgXoM@r{jfk z4n7fRF2K2f%E6oPYsD55o8&oAYCA35Kj3gG0Z-u?I8ha*Rh;M?E% z&iMeaeED)E%TjorhkTHq5OhSTq)`Ojvh7aOFrc6XX__KU6{H$at#TYVcmjs5L047S zmI2$+F=uW&rcKMkvJFHL$J-|&v`xuDH#E>lqFj!^L=4VjNEt)Z0)!!jt{KRb?7aYX z1Aymys69+>!Ua-BK`8@ebTk&jaZU#<7@N?exfI|+fOC#fd%ovQY%5~ml7mu)x%1}Y ztoHUd6;E?`lDo#TYI}wY1CBq3H@L!x0!y zQ7l!#xCCc0xR4NWf+Wo#WC9@tq!dk~3&`dC+6X2F9YqwBQbe={nh*lVIXyHi!u1Ti z_`<8u4YdYZNbr$39VaQ$G=UHjv5=>T_`Z)^E{A-6;w{H0LqsVU9rb7juIo++dem#* z;n6~X3l2v4SbKTmk`0z=s>MY7|ZSbAB0R?3?wjzM;Fj`+<-C)79{OKht%6!QFS=#RmrmF*G!ULb0gMo-=zvxjeiw zqV)4RA*9bRjI+~130a03YyfGNAx%>x3ScN2IHQP#f((FZXgG4D04Y88V7@qjnlel@+O|zPsnxAiOZl3emb?b_!^7DUt z>M(%A^DekxOEnA^13-O!Jxt5WiiN^T#@N-2GjPEngvf*tr6{7Gjl%G&y5l&1FirF9 zu<{z3nlAye7+IE$3>9e#%$?PWzP=$i#Dp#+4jimPRaLZ4$>aF(LFl@MG|j-602j%~ zh`~jIYV`=xGyxYGj`#E&I_1%Up9MjHe7^3qz}q=xG(KRK?8fs-dcIbQeN zbI)z0l;*=Q{2u_QRw}4ehEc6nv+div@ZInJJ6?F<1?=6s7jGOo^yf6xahzXTmW>Zy z_5r;7hXZ(b$0gA9TE&;88D^i~hJll13|A%6G^>^63Xo+$7z#*Pi|dq1L{x$aiHOM& z;1!exdqIc|F2v6Ops%-YY!Bmt!NI}*{PgW>v%#UEQn@_6R4fiqMn8-! zqw7ESIn?Fz-*r51wG`sb&6_v%R)#C0Qmvd5hS5(W8r>nKd|}bzMa8fh7OG*`S*cXg zSjuZgZRPWMJIgX>V$f6(Lby>_H2|QstyNSil`jofhQDy@r*7FaR4BYwDwSoaRB9;? zms`Uy+*1w1e>DsPl}ZJSF;X4*?U_X1wr%^t&)<9Rn=LIZGhXR_7BWuZxmL}ibrk~x zA(B*uORQS;mu1MZ6mgs)qOul?MT(GegskS(T*Q!xf|LEfhD~fxM!_QXweiN+u3fti zz}YKSt{{T(c|wRB7a~lg-2c{FZ&d)mvMfCOVBp|bTYixHcwwkuoS}*ooYS`9N+kk-!NEan+_-TA zfDJcXfBj6(MTZbv=Ryn|di~HI0La(nQ7V=YMG>czHbgWE|6-f;!3Q6lLI~-thN1Gr z&Rtlt=o83!Hf-B~uGN}KX$GWe4X}(8NSPwZQk>V(fTKqTP#ET@L^a4FPEn~G!T#Sp z4#O}(Dcd4AzjvYqtp1l7pZuPb@|yjB{3E&# z3}fE;%Mkb$OjCoVs>rfh$|qzDAxA%UF&Y~@luKols}d1UAY=+I3g~|25oD=E7)Dtv zrK=kTjivm%?MG`bzW5?$oOKq~+;-ddmc0M{D{{WySSY-S!$*5SNITTgR4=KO=e6P^ z0p~H8j8Q0s@O=|+4~7u2f-vgCtG|B~SsEjXXqHIX31DEPgEo1>^1zlYK$dCMFf4G+ zbAA19;pN}GidnO+L*B20W$FMFBxx;la1n!zHjgv~S(c*r_=`C5+DkA^6JZ!3k#boE zJUe+}IKkfy?p(j#rj-6l2!2r*ML2q_2ZxWojdMCKMP1#yp=y4ukV!MhSRe|Ip}+Sx zC>M@F(=tdYYmno3ZkA=;qldnepvTE|D^}p?XP&{0H{Q6KbM|m7V@F7VzP?^m!zyH4 zD`b)+MiNuRaRN=#kt7KyrJ$5OA%(adKs4#c{|D&NGq;^Pp8^0}b=8%dgb*va5NAmt zEGc71DQZol(Vj2k{ao-pQ8ij4r05?#RiBi<0D8PEUAk0JR0X9{X_}PrA|ZHVEaFH= z@kcJi@1ztN=W$jUF2S;_37b5V@>j}&g$vGbviz=7W%Z;?%A`!nr2I|ge*tF%Z>{6z R_JjZc002ovPDHLkV1m3z8S4N5 literal 0 HcmV?d00001 diff --git a/roo/src/main/resources/static/public/img/springroo-logo.png b/roo/src/main/resources/static/public/img/springroo-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9891fc3469e2d628a95d6553ac51ea36554df2 GIT binary patch literal 25823 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

;ybr>53$$!{CJ|?=Puk;#$PsZ&m>OCeL=_ zUCX@7vQ8uY^2;xmwock`E-}vq)A;~OpxqCA2;hBUelORKHMk6X; z4AA*BkT$GV8$gXd0L@^2UlDk7<$`bmsn6OltUy~s!)%)<*g6S72?0(JIWbTVHV?pY zUm0sR29`9oGSM0VIq=WUE$yk8U8KU9A5K%#!~!{AzJP#o0=pQPhWIf7pMuZ^#!6D? z?dZPIO@l#q86gmG*$;@%CMyalA9r=FPvtC6FN+sLI;F61vJfnypN|PAdfgfVW6zRE zdI~@#6Lx_4PX}!y@6IModuEV7E@{Nue#uKjr}? z#xn*#{wElJAwf@Qt+#DPX53eN3IwJCm;_)F7-I#Ioxxu?F9!A#&^I`%-@rfz*?3*E zH{6*q!_&y+mtQV@IKE>lh$jvFhqJ&q76Upchf*{Y0G|_~m%$xiY*a|vc<=y1>mEtZ zGbR<)R!v2!o%vT;ycp8go#RIL$)bQHDv+Rz005Th00|t7%JM&|&*?TrI*Wyc(KLjM zM%sFN94sT3{lpX*000CyNklByjMVco=^L>8=;ZV7<4>Mz|BJ*WNh2s z6&Y*hmr@H0qsgXv=2^kO10?yGhK0p&pt>l$4?xP65&@tg=x`EnL#*Q@=rPNYTO4g9 z6aZ&oVPRnwB=G%+y{El5O3`Q2X^(}48L*tWg@r}d&=?x;0q9zlCQrwUg14|3j#$pz z!ongeSi0GnORPKvm2@<+_dk$Mn=CBMg5}IDERJGUtQehdR2kD$Gjb1}#6Z;bkPy@T zl~cA3rA1(2G3>FNxrN11NKAs-j{b+9PK55j}-Tq+V{fie5)B`djje){D0FD{- z#y}vtcl0yqw8_H4Ojyp`!r~}I;piU#oCiPvG=f3iQytFN-dQ_kM5b-~D!!28Dk6F` zb_?DwB)&G2S`8K!nZ|PF78XYt4S@+K0;oFj2w#*R-QU=-);T)uM#Z2p=)3}q=b`qj zV)2v8v%5B>&ngQG^I+ z@Gw-KQ4G8-e?I!hX*A8k!n9b<+`{50q|z0s15_P409*yKZS;qncP-uQ%#G7lH;WfT z@&%kXF}Mwci`Ci^;Fk{AuC(^aEi4AGoVkU?Q3w&(`tD!h;+@dB8?mO%4f29^T+dwXx++j>eBH?46NDN*H85dAv<`@T zV87OJEi8s3mNU1UxrGIq0)=NPL@xsZzUEJf)E)x2E3$-Vf$SWmzt+ERFmh z5jg!eSXg8i!+x2a8RQQ+J^^sz5Qn#VT#+&9w#mXGoA9r4&St@P0GJCPFNH&GCh&_) z;t5Y_=Z+MPV_`Au81~K_0DOVMTS4^1S3f7>Ybr~-Udn_`78cn?L%3+9?LhAZOt=`} zY5=F}>{4c6H31D!ls|f=Z&_)CofZ~HBS(cZ2L_5YfH4oiWH34a)Oy^J*D`IFg+;c~ z5Og?g;7TTp2jdI^jbY$4CKM2(0KhQ-7{G2Y?}iXNz`P#71~7+vfu?V`yFSnCzrw;| bc<}!Lw@DCRefresh"; + } + callback(emptyData(data.draw)); + }); + } + + + /** + * Converts the first char of the given string to lower case. + * @param str the string to convert + * @returns the converted string + */ + function toLowerCaseFirst(str) { + if (str.length > 0) { + var value = str.charAt(0).toLowerCase(); + if (str.length > 1) { + value = value.concat(str.slice(1)); + } + return value; + } + } + + /** + * Returns the parent datatables whose id is given through + * the 'data-parent-table' attribute. + */ + function getParentDatatables(datatables) { + var parentTableId = getParentTableId(datatables); + // Validate if parent-table id has been specified and + // if the parent Datatable has been initialized + if (parentTableId && $.fn.dataTable.isDataTable($(parentTableId))) { + return $(parentTableId).DataTable(); + } + } + + /** + * Returns the parent table id when this datatables is a detail. + */ + function getParentTableId(datatables) { + var parentTableId = getDataValue(datatables, 'parent-table'); + if (parentTableId) { + return "#" + parentTableId; + } + } + + /** + * Returns the id of the selected row in the parent table, if any. + * @param datatables child datatables + * @returns the id of the parent datatables selected row + */ + function getParentSelectedRowId(datatables) { + var parentDatatables = getParentDatatables(datatables); + if (parentDatatables) { + var selected = parentDatatables.row({ + selected: true + }); + + if (selected.any()) { + return selected.data().id; + } + } + } + + /** + * Returns if the datatables has a related parent datatables + * @param datatables to find if it has a parent datatables + * @returns if there is a parent datatables + */ + function hasParentTable(datatables) { + var parentTableId = getParentTableId(datatables); + if (parentTableId) { + return true; + } + return false; + } + + /** + * Process the given Url to perform the following actions* + * - If the given datatables is not related to a parent one, it + * returns the given url as is. + * - If the url contains the '_PARENTID_' valuea and there is a related + * parent table, if the parent table has a selected row, its identifier + * is used to replace the '_PARENTID_' value in the given url. + * Otherwise no url is returned because it is considered as an invalid + * url. + * If the processed url is valid, the given id value is used to replace + * the '_ID_' parameter in the url + * @param datatables DataTable on which the calling should act upon + * @param url to process + * @param id (optional) identifier of the datatables row to act upon + * @returns the processed url + */ + function processUrl(datatables, url, id) { + var processedUrl = url; + // If it is a detail table, we have to get the parent id from + // the selected row in the parent table, and replace the + // _PARENTID_ variable in the given URL. + if (url && url.indexOf('_PARENTID_') > -1 && hasParentTable(datatables)) { + var parentRowId = getParentSelectedRowId(datatables); + if (parentRowId !== undefined) { + processedUrl = url.replace('_PARENTID_', parentRowId); + } else { + processedUrl = undefined; + } + } + + if (id !== undefined && processedUrl) { + processedUrl = processedUrl.replace('_ID_', id); + } + + return processedUrl; + } + + /** + * Process the given Url and the Datatables configuration to build + * an URL that contains the Datatables parameters. + * This function is useful when is necessary to make a petition + * to the server side without using AJAX. + * + * @param datatables DataTable on which the calling should act upon + * @param url to process + * @returns the processed url + */ + function getUrlWithDatatablesParams(datatables, url) { + + // Remove existing parameters + url = url.split("?")[0]; + + // Getting data from Datatables + var dtContext = datatables.context[0]; + var data = dtContext.oAjaxData; + + // Getting search value + var searchValue = data.search.value; + + // Getting order + var order = data.order; + + // Getting columns + var columns = data.columns; + + var sortParams = ""; + for (var i = 0; i < order.length; i++) { + if (order[i] !== null && order[i] !== undefined && + order[i].column !== null && order[i].column !== undefined) { + var columnName = columns[order[i].column].data; + var dir = order[i].dir; + + sortParams += "sort=" + columnName + "," + dir + "&"; + + } + } + if (sortParams.length > 0) { + sortParams = sortParams.substr(0, sortParams.length - 1); + } + + var datatablesColumns = ""; + for (i = 0; i < columns.length; i++) { + if (columns[i] !== null && columns[i] !== undefined && + columns[i].data !== null && columns[i].data !== undefined && + datatablesColumns.indexOf(columns[i].data) === -1) { + datatablesColumns += columns[i].data + ","; + } + } + if (datatablesColumns.length > 0) { + datatablesColumns = datatablesColumns.substr(0, datatablesColumns.length - 1); + datatablesColumns = "datatablesColumns=" + datatablesColumns; + } + + + // Build URL parameters + var hasParameters = false; + var params = ""; + if (searchValue != null && searchValue != "" && searchValue != undefined) { + if (hasParameters) { + params += "&"; + } + params += "search[value]=" + searchValue; + hasParameters = true; + } + + if (sortParams != null && sortParams != "" && sortParams != undefined) { + if (hasParameters) { + params += "&"; + } + params += sortParams; + hasParameters = true; + } + + if (datatablesColumns != null && datatablesColumns != "" && datatablesColumns != undefined) { + if (hasParameters) { + params += "&"; + } + params += datatablesColumns; + } + + return url + "?" + params; + + } + + /** + * Deletes the element whose id is the one in the datatables + * row whose _delete_ button has been selected, and the + * the opened modal confirmacion has been accepted + * (see modal-confirm-delete.html) + * @param datatables DataTable on which the calling should act upon + */ + function deleteElement(datatables) { + var $token = $("meta[name='_csrf']"); + var $header = $("meta[name='_csrf_header']"); + + var tableId = getTableId(datatables); + var rowId = $('#' + tableId + 'DeleteRowId').data('row-id'); + var url = getDeleteUrl(datatables, rowId); + + $.ajax({ + url: url, + type: 'DELETE', + beforeSend: function(request) { + if ($token != null && $token.length > 0 && $header != null && $header.length > 0) { + request.setRequestHeader($header.attr("content"), $token.attr("content")); + } + } + }) + .done(function(result) { + var $deleteSuccess = $('#' + tableId + 'DeleteSuccess'); + $deleteSuccess.modal(); + datatables.ajax.reload(); // Refresh Datatables + }) + .fail(function(jqXHR, status) { + var $deleteError = $('#' + tableId + 'DeleteError'); + $deleteError.modal(); + }); + } + + /** + * Returns the URL to load the data for a Datatables. The value + * is defined through a 'data-load-url' attribute in the + * Datatables table tag. + * @param datatables DataTable on which the calling should act upon + */ + function getLoadUrl(datatables) { + var url = getDataValue(datatables, 'load-url'); + return processUrl(datatables, url); + } + + /** + * Returns the URL to create a new element for the Datatables. + * The URL is processed to replace any parameters. + * + * @param datatables DataTable on which the calling should act upon + */ + function getCreateUrl(datatables) { + var url = getDataCreateUrl(datatables); + return processUrl(datatables, url); + } + + /** + * Returns the URL to create a new element for the Datatables + * as defined in the table data attributes. + * The value is defined in the Datatables table tag with a + * 'data-create-url-function' as a function which returns the URL + * or, if it is not defined, the value of the attribute + * 'data-create-url' to be used as the URL. + * + * @param datatables DataTable on which the calling should act upon + */ + function getDataCreateUrl(datatables) { + var urlFunction = getDataValue(datatables, 'create-url-function'); + var url = urlFunction ? $[urlFunction]() : getDataValue(datatables, 'create-url'); + return url; + } + + /** + * Returns the URL to show the details of an element of the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-show-url' as the URL to use. + * The URL contains the text *_ID_* in the place where + * the selected element Id has to be inserted. + * + * @param datatables DataTable on which the calling should act upon + * @param id identifier of the element to edit + */ + function getShowUrl(datatables, id) { + if (id == null || id === "null") { + return null; + } + var url = getDataValue(datatables, 'show-url'); + return processUrl(datatables, url, id); + } + + /** + * Returns the URL to edit an element of the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-edit-url' as the URL to use. + * The URL contains the text *_ID_* in the place where + * the selected element Id has to be inserted. + * + * @param datatables DataTable on which the calling should act upon + * @param id identifier of the element to edit + */ + function getEditUrl(datatables, id) { + var url = getDataValue(datatables, 'edit-url'); + return processUrl(datatables, url, id); + } + + /** + * Returns the URL to remove an element of the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-delete-url' as the URL to use. + * The URL contains the text *_ID_* in the place where + * the selected element Id has to be inserted. + * + * @param datatables DataTable on which the calling should act upon + */ + function getDataDeleteUrl(datatables) { + var url = getDataValue(datatables, 'delete-url'); + return url; + } + + /** + * Returns the URL to remove an element of the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-delete-url' as the URL to use. + * + * The URL contains the text *_ID_* in the place where + * the selected element Id has to be inserted, AND it is + * replaced with the provided id. + * + * @param datatables DataTable on which the calling should act upon + * @param id identifier of the element to remove + */ + function getDeleteUrl(datatables, id) { + var url = getDataDeleteUrl(datatables); + return processUrl(datatables, url, id); + } + + /** + * Returns the URL to remove a list of elements from the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-delete-batch-url' as the URL to use. + * The URL contains the text *_ID_* in the place where + * the selected elements Ids have to be inserted. + * + * @param datatables DataTable on which the calling should act upon + */ + function getDataDeleteBatchUrl(datatables) { + var url = getDataValue(datatables, 'delete-batch-url'); + return url; + } + + /** + * Returns the URL to remove a list of elements from the Datatables. + * The value is defined in the Datatables table tag with a + * 'data-delete-batch-url' as the URL to use. + * The URL contains the text *_ID_* in the place where + * the selected elements Ids have to be inserted, and it is + * replaced with the provided idlist. + * + * @param datatables DataTable on which the calling should act upon + * @param idlist list of identifiers of the elements to remove + */ + function getDeleteBatchUrl(datatables, idlist) { + var url = getDataDeleteBatchUrl(datatables); + return processUrl(datatables, url, idlist); + } + + /** + * Returns the 'data-name' attribute value of a datatables. + * @param datatables DataTable on which the calling should act upon + * @param name the name of the data attribute to return the value of + */ + function getDataValue(datatables, name) { + var $dt = jQueryTable(datatables); + return $dt.data(name); + } + + /** + * Returns all the 'data-*' attributes of a datatables. + * @param datatables DataTable on which the calling should act upon + */ + function getAllDataValues(datatables) { + var $dt = jQueryTable(datatables); + return $dt.data(); + } + + /** + * Returns the jQuery object for the given datatables element. + */ + function jQueryTable(datatables) { + return $(datatables.table().node()); + } + + /** + * Returns the table id attribute for the given datatables element. + */ + function getTableId(datatables) { + var $jQueryTable = jQueryTable(datatables); + return $jQueryTable.attr('id'); + } + + /** + * Generates a JSON object with the necessary data for indicating a + * DataTables object that 0 elements have been found. + * This is used for details related tables, when a parent table + * row is not selected. + * + * @param draw DataTables request counter + * @returns {json} JSON object with empty data + */ + function emptyData(draw) { + return { + 'data': [], + 'draw': draw, + 'error': null, + 'recordsFiltered': '0', + 'recordsTotal': '0' + }; + } + + /** + * This function will be called when DataTables has been fully + * initialised and data loaded. + */ + function onInitComplete(oSettings, json) { + var datatables = this.DataTable(); + // Save the selected row to state + saveSelectedRowToState(datatables, oSettings, json); + // Register checkboxes + registerCheckBoxesEvents(datatables); + } + + /** + * If a row is selected, store it in the persisted table state + * so if the user goes to another page and returns, the current + * selected row is still selected. + * @param datatables the Datatables element + * @param oSettings DataTable object options + * @param json + */ + function saveSelectedRowToState(datatables, oSettings, json) { + var state = datatables.state; + datatables.on('select', function(e, dt, type, indexes) { + if (type === 'row') { + var rowSelectedId = datatables.rows(indexes).ids()[0]; + state.loaded().rowSelectedId = rowSelectedId; + state.save(); + } + }); + datatables.on('deselect', function(e, dt, type, indexes) { + if (type === 'row') { + state.loaded().rowSelectedId = undefined; + state.save(); + } + }); + if (!state.loaded()) { + oSettings.oLoadedState = datatables.state(); + } + } + + /** + * Loads a previously persisted datatables state. + * @param settings DataTable object options + * @param data DataTable object data + */ + function loadFromState(settings, data) { + var datatables = this.DataTable(); + loadSelectedRowFromState(datatables, data); + } + + /** + * Loads a previously selected row id from the persisted state. + * @param settings DataTable object options + * @param data DataTable object data + */ + function loadSelectedRowFromState(datatables, data) { + var state = datatables.state; + if (state.loaded()) { + var rowSelectedId = state.loaded().rowSelectedId; + if (rowSelectedId) { + data.rowSelectedId = rowSelectedId; + } + } + } + + /** + * Registers events for the given datatables + */ + function registerEvents(datatables) { + registerDeleteModalEvents(datatables); + registerAddModalEvents(datatables); + registerToParentEvents(datatables); + registerOnDrawFinishesEvents(datatables); + } + + /** + * This function registers all the necessary actions to execute + * when the provided datatables is completly drawed. + */ + function registerOnDrawFinishesEvents(datatables) { + // When this datatable is re-drawed, the + // following actions will be executed + datatables.on('draw.dt', function() { + // Register events to the new included checkboxes + registerCheckBoxesEvents(datatables); + }); + } + + /** + * Registers events related to the checkboxes of the given + * datatables. + */ + function registerCheckBoxesEvents(datatables) { + // Getting the table id + var tableId = getTableId(datatables); + // Obtain all checkboxes for this table + var checkBoxes = jQuery("#" + tableId + " input:checkbox"); + // Register change event for every checkbox. Every time that some checkbox + // changes, validates if the delete batch button should be enabled or not + jQuery.each(checkBoxes, function(item) { + jQuery(this).change(function() { + var rows_selected = datatables.columns().checkboxes.selected(); + if (rows_selected.join(",") === "") { + datatables.button('delete:name').disable(); + } else { + datatables.button('delete:name').enable(); + } + }); + }); + + // Re-initialize the delete batch button + var rows_selected = datatables.columns().checkboxes.selected(); + if (rows_selected.join(",") === "") { + datatables.button('delete:name').disable(); + } else { + datatables.button('delete:name').enable(); + } + + } + + /** + * Registers the events related to the delete modals, so the + * modal knows the id of the row to delete. + */ + function registerDeleteModalEvents(datatables) { + var tableId = getTableId(datatables); + var $deleteConfirm = $('#' + tableId + 'DeleteConfirm'); + + // When the delete element modal is opened, copy the current + // element id to be deleted to the 'TABLE_ID + DeleteRowId' + // element + $deleteConfirm.on('show.bs.modal', function(e) { + // Get data-row-id attribute of the clicked element + var rowId = jQuery(e.relatedTarget).data('row-id'); + // Populate the row-id data attribute in the modal + $('#' + tableId + 'DeleteRowId').data('row-id', rowId) + }); + + $('#' + tableId + 'DeleteButton').on('click', function() { + deleteElement(datatables); + }); + } + + /** + * When a table is linked to parent table, for a master detail list + * for example, it registers the row selection events in the parent + * table to update the data in the child table. + */ + function registerToParentEvents(datatables) { + var parentDatatables = getParentDatatables(datatables); + + if (parentDatatables) { + // Register to de/select events + parentDatatables.on('select', function() { + datatables.button('add:name').enable(); + datatables.ajax.reload(); + }); + + parentDatatables.on('deselect', function() { + datatables.button('add:name').disable(); + datatables.ajax.reload(); + }); + + // Register to reload finished event, needed when the selected row has + // been deleted in the parent table or any other change + parentDatatables.on('xhr.dt', function() { + datatables.ajax.reload(); + }); + + datatables.button('add:name').disable(); + } + } + + /** + * Registers the events related to the delete modals, so the + * modal knows the id of the row to delete. + */ + function registerAddModalEvents(datatables) { + var parentDatatables = getParentDatatables(datatables); + + // The add modal dialog is only used in child datatables + if (parentDatatables) { + var tableId = getTableId(datatables); + + $('#' + tableId + 'AddButton').on('click', function() { + var url = getCreateUrl(datatables); + $addForm = $('#' + tableId + 'AddForm'); + var params = $addForm.serialize(); + $.ajax({ + type: $addForm.attr('method'), + url: url, + data: params, + success: function(data) { + datatables.ajax.reload(); + } + }); + }); + } + } + + /** + * Renders the tools column, with the buttons to perform operations + * on the table rows. + */ + function renderTools(data, type, full, meta) { + var datatables = new $.fn.dataTable.Api(meta.settings); + var tableId = getTableId(datatables); + var rowId = data; + var buttons = '
'; + + var showUrl = getShowUrl(datatables, rowId); + // Check if the show will be inline + var showInline = getDataValue(datatables, 'show-inline'); + if (showUrl && !showInline) { + buttons = buttons.concat(''); + }else if(showUrl && showInline){ + buttons = buttons.concat(''); + } + + var editUrl = getEditUrl(datatables, rowId); + if (editUrl) { + buttons = buttons.concat(''); + } + + var deleteUrl = getDeleteUrl(datatables, rowId); + if (deleteUrl) { + buttons = buttons.concat(''); + } + + buttons = buttons.concat('
'); + return buttons; + } + + + /** + * This method tries to display the show view of the selected record + * expanding the selected row. + */ + function showInline(showButton, datatables, showUrl){ + var tr = showButton.closest('tr'); + var row = datatables.row( tr ); + if ( row.child.isShown() ) { + // This row is already open - close it + $(showButton).attr("aria-expanded", "false"); + row.child.hide(); + } + else { + $(showButton).attr("aria-expanded", "true"); + $.ajax({ + url: showUrl + "/inline", + dataType: 'html' + }).done(function(data) { + // Open this row + row.child(data).show(); + }).fail(function(data){ + // Show error in new row + row.child("
ERROR: An error occurred while trying to obtain more info.
").show(); + }); + } + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables Advanced Extension API + * + * For complete documentation, please refer to the docs/api directory or the + * DataTables site + */ + + // Local variables to improve compression + var apiRegister = DataTable.Api.register; + + apiRegister('advanced()', function() { + return this.iterator('table', function(settings) { + DataTable.advanced.init(settings); + }); + }); + + apiRegister('advanced.getTableId()', getTableId); + apiRegister('advanced.getCreateUrl()', getCreateUrl); + apiRegister('advanced.getEditUrl()', getEditUrl) + apiRegister('advanced.getDeleteUrl()', getDeleteUrl); + apiRegister('advanced.getDeleteBatchUrl()', getDeleteBatchUrl); + apiRegister('advanced.getShowUrl()', getShowUrl); + apiRegister('advanced.getDataValue()', getDataValue); + apiRegister('advanced.processUrl()', processUrl); + + apiRegister('advanced.getCreateButton()', createButton); + apiRegister('advanced.getDeleteBatchButton()', deleteBatchButton); + apiRegister('advanced.getExportCsvButton()', exportCsvButton); + apiRegister('advanced.getExportExcelButton()', exportExcelButton); + apiRegister('advanced.getExportPdfButton()', exportPdfButton); + + apiRegister('advanced.showInline()', showInline); + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Initialization + */ + + // DataTables creation - check if advanced has been defined in the options. + $(document).on('preInit.dt.dtadvanced', function(e, settings) { + if (e.namespace !== 'dt') { + return; + } + + // If the 'advanced' option has been specified, + // initialize the advanced configuration for this + // DataTable. + if (settings.oInit.advanced !== undefined) { + DataTable.advanced.init(settings); + } + + }); + + return DataTable.advanced; +})); diff --git a/roo/src/main/resources/static/public/js/datatables-defaults.js b/roo/src/main/resources/static/public/js/datatables-defaults.js new file mode 100644 index 0000000000..ab247078e4 --- /dev/null +++ b/roo/src/main/resources/static/public/js/datatables-defaults.js @@ -0,0 +1,29 @@ +// IIFE - Immediately Invoked Function Expression +(function(extendDatatables) { + + // The global jQuery object is passed as a parameter + extendDatatables(window.jQuery, window, document); + +}(function($, window, document) { + + // The $ is now locally scoped, it won't collide with other libraries + + // Listen for the jQuery ready event on the document + // READY EVENT BEGIN + $(function() { + // Initialize all datatables in current page + $('table[data-datatables="true"]').each(function(){ + // Use the advanced extension to auto-configure all + // advanced features (ajax, export, add, edit, show, delete, etc.) + $(this).DataTable({ + mark: true, + advanced: true + }); + }); + }); + + // READY EVENT END + //console.log('The DOM may not be ready'); + + // The rest of code goes here! +})); \ No newline at end of file diff --git a/roo/src/main/resources/static/public/js/datetimepicker-defaults.js b/roo/src/main/resources/static/public/js/datetimepicker-defaults.js new file mode 100644 index 0000000000..3d114d93aa --- /dev/null +++ b/roo/src/main/resources/static/public/js/datetimepicker-defaults.js @@ -0,0 +1,107 @@ +(function(jQuery) { + jQuery(document).ready(function() { + + /* + * jQuery Utilities ================================================== + */ + /** + * Select the most switchable time format for time selectod related to + * requiered format + * + * @param format + * @returns time format + */ + function getSelectorTimeFormat(format) { + // + if (format.search(/h{1,2}/) > -1 && format.search(/[aA]/) > -1) { + if (format.search(/[A]/) > -1) { + return "hh:mm A"; + } else { + return "hh:mm a"; + } + } + return "HH:mm"; + } + + // Use the same locale than MomentJs + // (set it before setDateFormater as setLocale override formatter) + jQuery.datetimepicker.setLocale(moment.locale()); + + // Define parse/format date using moment library + jQuery.datetimepicker.setDateFormatter({ + parseDate : function(date, format) { + var d = moment(date, format); + return d.isValid() ? d.toDate() : false; + }, + + formatDate : function(date, format) { + return moment(date).format(format); + } + }); + + jQuery(".datetimepicker").each(function(index) { + var $input = jQuery(this); + var options = { + step : 5 + }; + + var pattern = $input.attr("data-dateformat"); + var value = $input.attr("data-timestep"); + + if (value) { + try { + options.step = parseInt(value); + } catch (e) { + timeStep = 5; + } + } + + // FormatDate YYYY/MM/DD + value = $input.attr("data-startdate"); + if (value) { + options.startDate = value; + } + value = $input.attr("data-mindate"); + if (value) { + options.minDate = value; + } + value = $input.attr("data-maxdate"); + if (value) { + options.maxDate = value; + } + + // FormatTime : "HH:mm" + value = $input.attr("data-mintime"); + if (value) { + options.minTime = value; + } + value = $input.attr("data-maxtime"); + if (value) { + options.maxTime = value; + } + value = $input.attr("data-allowtimes"); + if (value) { + options.allowTimes = value.split(","); + } + + if (isNotEmpty(pattern)) { + var momentPattern = moment.javaToMomentDateFormat(pattern); + jQuery.extend(options, { + format : momentPattern, + datepicker : moment.isDateFormatDate(momentPattern), + timepicker : moment.isDateFormatTime(momentPattern), + formatDate : "YYYY/MM/DD", + formatTime : getSelectorTimeFormat(momentPattern) + }); + } else { + var emptyMomentPattern = moment.javaToMomentDateFormat(); + jQuery.extend(options, { + format : emptyMomentPattern, + formatDate : "YYYY/MM/DD", + formatTime : "HH:mm" + }); + } + $input.datetimepicker(options); + }); + }); +})(jQuery); \ No newline at end of file diff --git a/roo/src/main/resources/static/public/js/inputmask-defaults.js b/roo/src/main/resources/static/public/js/inputmask-defaults.js new file mode 100644 index 0000000000..f3a299bb5d --- /dev/null +++ b/roo/src/main/resources/static/public/js/inputmask-defaults.js @@ -0,0 +1,30 @@ +(function(jQuery) { + jQuery(document).ready(function() { + + /* + Inputmask.extendDefaults({ + 'autoUnmask' : true + }); + */ + + jQuery(".inputmask").each(function(index) { + var $input = jQuery(this); + var options = { + removeMaskOnSubmit : true + }; + + var pattern = $input.attr("data-inputmask-mask"); + if (pattern) { + options.mask = pattern; + } else { + var alias = $input.attr("data-inputmask-alias"); + if (alias) { + options.alias = alias; + } else { + throw "missing input initialization value on (id='"+this.id+"' name='"+this.name+"')"; + } + } + $input.inputmask(options); + }); + }); +})(jQuery); \ No newline at end of file diff --git a/roo/src/main/resources/static/public/js/main.js b/roo/src/main/resources/static/public/js/main.js new file mode 100644 index 0000000000..b704282624 --- /dev/null +++ b/roo/src/main/resources/static/public/js/main.js @@ -0,0 +1,70 @@ +(function(jQuery) { + jQuery(document).ready( + function() { + + //dropdown + jQuery('ul.dropdown-menu [data-toggle=dropdown]').on( + 'click', + function(event) { + event.preventDefault(); + event.stopPropagation(); + jQuery(this).parent().siblings() + .removeClass('open'); + jQuery(this).parent().toggleClass('open'); + }); + + //tooltip + jQuery('[data-toggle="tooltip"]').tooltip(); + + }); +})(jQuery); + +/** + * Checks if an object in JavaScript is undefined, null or empty string + * + * @param obj + * @returns {Boolean} + */ +function isEmpty(obj) { + if (jQuery.isPlainObject(obj)) { + return jQuery.isEmptyObject(obj); + } else if (jQuery.isArray(obj)) { + return 0 === obj.length; + } else if (typeof obj === "string") { + return (isNull(obj) || 0 === obj.length); + } + return isNull(obj); +} + +/** + * Checks if an object in JavaScript is undefined or null + * + * @param obj + * @returns {Boolean} + */ +function isNull(obj) { + if (typeof obj === "undefined" || obj == null) { + return true; + } + return false; +} + +/** + * Checks if an object in JavaScript is defined and not null + * + * @param obj + * @returns {Boolean} + */ +function isNotNull(obj) { + return !isNull(obj); +} + +/** + * Checks if an object in JavaScript is undefined, null or empty string + * + * @param obj + * @returns {Boolean} + */ +function isNotEmpty(obj) { + return !isEmpty(obj); +} diff --git a/roo/src/main/resources/static/public/js/moment-defaults.js b/roo/src/main/resources/static/public/js/moment-defaults.js new file mode 100644 index 0000000000..e8f4cf963a --- /dev/null +++ b/roo/src/main/resources/static/public/js/moment-defaults.js @@ -0,0 +1,88 @@ +(function(jQuery) { + + moment().format(); + + /** + * Convert Java's SimpleDateFormat to momentJS formatDate. Takes a Java + * pattern + * (http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html) + * and turns it into the expected momentJS formatDate + * (http://momentjs.com/docs/#/parsing/string-format/). + * + * @param pattern + * SimpleDateFormat pattern + * @return moment pattern (if 'pattern' is ommited return defautl + * pattern) + */ + moment.javaToMomentDateFormat = function (pattern) { + if (pattern) { + // Year + if (pattern.search(/y{3,}/g) >= 0) { + pattern = pattern.replace(/y{3,}/g, "YYYY"); // yyyy to + // yy + } else if (pattern.search(/y{2}/g) >= 0) { // yy to YY + pattern = pattern.replace(/y{2}/g, "YY"); + } + + // Day + if (pattern.search(/d{2,}/g) >= 0) { // dd to DD + pattern = pattern.replace(/d{2,}/g, "DD"); + } else if (pattern.search(/d{1}/g) >= 0) { // d to D + pattern = pattern.replace(/d{1}/g, "D"); + } else if (pattern.search(/D{1,}/g) >= 0) { // D,DD, DDD to DDD + pattern = pattern.replace(/D{1,}/g, "DDD"); + } + + // Day in week + if (pattern.search(/E{4,}/g) >= 0) { // EEEE to dddd + pattern = pattern.replace(/E{4,}/g, "dddd"); + } else if (pattern.search(/E{2,3}/g) >= 0) { // EEE to ddd + pattern = pattern.replace(/E{2,3}/g, "ddd"); + } + + // Day in week (number) + if (pattern.search(/F{1}/g) >= 0) { // F to e + pattern = pattern.replace(/F{1}/g, "e"); + } + + // week of the year + if (pattern.search(/w{1,}/g) >= 0) { // ww to WW + pattern = pattern.replace(/w{1,}/g, "WW"); + } + } else { + return "YYYY/MM/DD HH:mm"; + } + + return pattern; + } + + /** + * Informs if date format (momentJS) includes date information + * + * @param format + * string + * @returns true if !format or format contains ('YQDMdw') + */ + moment.isDateFormatDate = function (format) { + if (!format) { + return true; + } + return format.search(/[YQDMdw]/) > -1; + } + + /** + * Informs if date format (ISO 8601) includes time information + * + * @param format + * string + * @returns true if !format or format contains ('HmAasSZ') + */ + moment.isDateFormatTime = function (format) { + if (!format) { + return true; + } + return format.search(/[HhmAasSZ]/) > -1; + ; + } + +})(jQuery); diff --git a/roo/src/main/resources/static/public/js/moment-locale-es.js b/roo/src/main/resources/static/public/js/moment-locale-es.js new file mode 100644 index 0000000000..fbf94e406e --- /dev/null +++ b/roo/src/main/resources/static/public/js/moment-locale-es.js @@ -0,0 +1,73 @@ +//! moment.js locale configuration +//! locale : spanish (es) +//! author : Julio Napurí : https://github.com/julionc + +// ROO-3814 Remove var "monthsShortDot" and "if" that assigns it. + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['moment'], factory) : + factory(global.moment) +}(this, function (moment) { 'use strict'; + + var es = moment.defineLocale('es', { + months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'), + monthsShort : 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'), + monthsParseExact : true, + weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'H:mm', + LTS : 'H:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D [de] MMMM [de] YYYY', + LLL : 'D [de] MMMM [de] YYYY H:mm', + LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm' + }, + calendar : { + sameDay : function () { + return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + nextDay : function () { + return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + nextWeek : function () { + return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + lastDay : function () { + return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + lastWeek : function () { + return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + sameElse : 'L' + }, + relativeTime : { + future : 'en %s', + past : 'hace %s', + s : 'unos segundos', + m : 'un minuto', + mm : '%d minutos', + h : 'una hora', + hh : '%d horas', + d : 'un día', + dd : '%d días', + M : 'un mes', + MM : '%d meses', + y : 'un año', + yy : '%d años' + }, + ordinalParse : /\d{1,2}º/, + ordinal : '%dº', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } + }); + + return es; + +})); \ No newline at end of file diff --git a/roo/src/main/resources/static/public/js/select2-defaults.js b/roo/src/main/resources/static/public/js/select2-defaults.js new file mode 100644 index 0000000000..6e45799dfb --- /dev/null +++ b/roo/src/main/resources/static/public/js/select2-defaults.js @@ -0,0 +1,49 @@ +// IIFE - Immediately Invoked Function Expression +(function(extendSelect2) { + + // The global jQuery object is passed as a parameter + extendSelect2(window.jQuery, window, document); + +}(function($, window, document) { + + // The $ is now locally scoped, it won't collide with other libraries + + // Listen for the jQuery ready event on the document + // READY EVENT BEGIN + $(function() { + + // The DOM is ready! + //console.log('The DOM is ready'); + + // Init select simple + $('.dropdown-select-simple').select2({ + debug : false, + theme : 'bootstrap', + allowClear : true, + }); + + // Init select with AJAX search + $('.dropdown-select-ajax').select2({ + debug : false, + theme : 'bootstrap', + allowClear : true, + ajax : { + data : function(params) { + // set search params names to match with GlobalSearch and + // Pageable arguments + var query = { + 'search[value]' : params.term, + 'page' : params.page - 1, + }; + return query; + } + } + }); + }); + + // READY EVENT END + //console.log('The DOM may not be ready'); + + // The rest of code goes here! +})); + diff --git a/roo/src/main/resources/static/public/js/validation-defaults.js b/roo/src/main/resources/static/public/js/validation-defaults.js new file mode 100644 index 0000000000..a92da83d58 --- /dev/null +++ b/roo/src/main/resources/static/public/js/validation-defaults.js @@ -0,0 +1,233 @@ +(function(jQuery) { + jQuery(document) + .ready( + function() { + + function getLanguage() { + // usamos el locale de momentjs + moment.locale(); + } + + jQuery.validator.setDefaults({ + ignoreTitle : true + }); + + /** + * Initialize jQuery Validator methods + */ + /** + * Date/time validation with format + * + * @name jQuery.validator.methods.number + * @type Boolean + */ + jQuery.validator.addMethod("dateformat", function(value, element, params) { + if (this.optional(element)) { + return true; + } + if (params === "DEFAULT") { + return moment(value, moment.javaToMomentDateFormat()).isValid(); + } else { + return moment(value, params, true).isValid(); + } + }, "Please enter a correct date/time"); + + /** + * Replaces the standard number validation to support number with comma. + * + * @name jQuery.validator.methods.number + * @type Boolean + */ + jQuery.validator.methods.number = function(value, element) { + return this.optional(element) || Inputmask.isValid(value, { + alias : "numeric" + }); + }; + + /** + * Replaces the standar min validation to support number with comma. + * + * @name jQuery.validator.methods.number + * @type Boolean + */ + jQuery.validator.methods.min = function(value, element, params) { + var localizedValue = Inputmask.unmask(value, { + alias : "numeric", + unmaskAsNumber : true + }); + return this.optional(element) || localizedValue >= params; + }; + + /** + * Replaces the standar max validation to support number with comma. + * + * @name jQuery.validator.methods.number + * @type Boolean + */ + jQuery.validator.methods.max = function(value, element, params) { + var localizedValue = Inputmask.unmask(value, { + alias : "numeric", + unmaskAsNumber : true + }); + return this.optional(element) || localizedValue <= params; + }; + + /** + * Replaces the standard range validation to support number with comma. + * + * @name jQuery.validator.methods.number + * @type Boolean + */ + jQuery.validator.methods.range = function(value, element, params) { + var localizedValue = Inputmask.unmask(value, { + alias : "numeric", + unmaskAsNumber : true + }); + return this.optional(element) + || (localizedValue >= params[0] && localizedValue <= params[1]); + }; + + /** + * Return true if the field value matches the given RegExp + * + * The difference between `pattern` method is than this one + * use parameter as expression literally (`pattern` includes + * prefix and suffix). + */ + $.validator.addMethod("regexp", function(value, element, param) { + if (this.optional(element)) { + return true; + } + if (typeof param === "string") { + param = new RegExp(param); + } + return param.test(value); + }, "Invalid format."); + + /** + * jquery.inputmask rule: delegates on inputmask control + */ + jQuery.validator.addMethod("inputmask", function(value, element, params) { + if (this.optional(element)) { + return true; + } + var $inputmask = jQuery(element); + return $inputmask.inputmask && $inputmask.inputmask("isComplete"); + }, "Please enter a valid value."); + + // Form validation init + jQuery("form.validate") + .each( + function(index) { + var $form = $(this); + + // see options at https://jqueryvalidation.org/documentation/ + $form + .validate({ + highlight : function(element) { + var $element = $(element); + // añadir marca error + $element.closest('.form-group').addClass('has-error has-feedback'); + // añadir span con icono + var iconSpan = $element.parent().find('span.form-control-feedback'); + if (!iconSpan.length) { + $element + .after(''); + } + }, + unhighlight : function(element) { + var $element = $(element); + // añadir marca error + $element.closest('.form-group').removeClass('has-error has-feedback'); + // quitar span con icono + $element.parent().find('span.form-control-feedback.glyphicon-remove') + .remove(); + // limpiar errores + if ($element.parent('.input-group').length) { + $element.parent('.input-group').parent().find( + 'span.help-block[id=' + $element.attr('id') + '-error]') + .remove(); + + } else { + $element.parent().find( + 'span.help-block[id=' + $element.attr('id') + '-error]') + .remove(); + } + }, + errorElement : 'span', + errorClass : 'help-block', + errorPlacement : function(error, element) { + var $element = $(element); + + var $previousErrors; + if ($element.parent('.input-group').length) { + $previousErrors = $element.parent('.input-group').parent() + .find('span.help-block[id=' + $element.attr('id') + '-error]'); + } else { + $previousErrors = $element.parent().find( + 'span.help-block[id=' + $element.attr('id') + '-error]'); + } + + if ($previousErrors.length === 1) { + $previousErrors.replaceWith(error); + } else { + if ($previousErrors.length > 1) { + // mas de un error limpiamos + $previousErrors.remove(); + } + // insertar error + if ($element.parent('.input-group').length) { + error.insertAfter($element.parent()); + } else { + $element.parent().append(error); + } + } + + } + }); + + // Iterate form inputs to set validation rules and messages + $form.find("input,textarea,select").each(function(index) { + var $input = $(this); + var data = $input.data(); + + // this input validation rules + var rules = { + required : data.required, + messages : {} + }; + if (isNotNull(data.missing)) { + rules.messages.required = data.missing + } + if (isNotNull(data.invalid)) { + rules.messages.remote = data.invalid + } + + // inputmaks + if ($input.hasClass("inputmask")) { + rules["inputmask"] = true; + if (isNotNull(data.invalid)) { + rules.messages.inputmask = data.invalid + } + } + // datetimepicker + if (isNotEmpty(data.dateformat)) { + rules["dateformat"] = moment.javaToMomentDateFormat(data.dateformat); + if (isNotNull(data.invalid)) { + rules.messages.dateformat = data.invalid + } + // datetimepicker without format + } else if ($input.hasClass("datetimepicker")) { + rules["dateformat"] = "DEFAULT"; + if (isNotNull(data.invalid)) { + rules.messages.dateformat = data.invalid + } + } + + $input.rules("add", rules); + }); + }); + }); +})(jQuery); + + diff --git a/roo/src/main/resources/templates/accessibility.html b/roo/src/main/resources/templates/accessibility.html new file mode 100644 index 0000000000..f486646c65 --- /dev/null +++ b/roo/src/main/resources/templates/accessibility.html @@ -0,0 +1,61 @@ + + + + + Accessibility - Spring Roo application + + + + +
+ +
+ + +
+ + +
+ +
+
+

Accessibility

+

Accessibility policy application

+

+ Spring Roo Application is committed to ensuring the accessibility of + its web content to people with disabilities. All of the content on + our website will meet + W3C WAI's Web Content Accessibility Guidelines 2.0, Level AA + conformance. Any issues should be reported to + springroo@disid.com. + The technologies that is depended to access the accessible content are HTML, CSS and Javascript. +

+
+
+ +
+ +
+ + +
+ +
+ + + + + +
+
+ + + + \ No newline at end of file diff --git a/roo/src/main/resources/templates/books/create.html b/roo/src/main/resources/templates/books/create.html new file mode 100644 index 0000000000..dabe34da10 --- /dev/null +++ b/roo/src/main/resources/templates/books/create.html @@ -0,0 +1,153 @@ + + + + + + Create Book - roo - SpringRoo Application + + + + + + + + +
+ +
+ + +
+ + +
+
+ +

Create Book

+ + +
+ +
+ Book data + +
+ +
+ + + Error message. +
+
+
+ +
+ + + Error message. +
+
+
+ +
+ + + Error message. +
+
+
+ + + +
+
+ + +
+
+ +
+ + +
+ +
+ +
+ + +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/roo/src/main/resources/templates/books/edit.html b/roo/src/main/resources/templates/books/edit.html new file mode 100644 index 0000000000..e6d39a44be --- /dev/null +++ b/roo/src/main/resources/templates/books/edit.html @@ -0,0 +1,171 @@ + + + + + + Edit Book - Spring Roo application + + + + + + + + + +
+ +
+ + +
+ + +
+ +
+ +

Edit Book

+ + +
+ + + + +
+

Warning! This record has been updated by an other user.

+
+ +
+
+ +
+
+ +
+ + +
+ Book data + +
+ +
+ + + Error message. +
+
+
+ +
+ + + Error message. +
+
+
+ +
+ + + Error message. +
+
+
+ + + +
+
+
+ +
+
+ +
+
+
+ +
+ + +
+ +
+ +
+ + +
+ +
+ + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + diff --git a/roo/src/main/resources/templates/books/list.html b/roo/src/main/resources/templates/books/list.html new file mode 100644 index 0000000000..d7e1fe24ca --- /dev/null +++ b/roo/src/main/resources/templates/books/list.html @@ -0,0 +1,98 @@ + + + + + + List Book - roo - SpringRoo Application + + + + + +
+ +
+ + +
+ + +
+
+ +

Books

+ + +
+ + + + + + + + + + + + + + + + + + + + +
Book List
titleauthorisbnTools
titleauthorisbnTools
+ +
+
+
+
+
+
+
+ + + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + + + + +
+
+ + + + diff --git a/roo/src/main/resources/templates/books/show.html b/roo/src/main/resources/templates/books/show.html new file mode 100644 index 0000000000..92311c36f5 --- /dev/null +++ b/roo/src/main/resources/templates/books/show.html @@ -0,0 +1,86 @@ + + + + + Show Book - Spring Roo application + + + + + +
+ +
+ + +
+ + +
+
+ + +

Show Book

+ +
+

Book data

+
    +
  • + title + titleValue +
  • +
  • + author + authorValue +
  • +
  • + isbn + isbnValue +
  • +
+
+ + +
+
+ Edit +
+
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + + + + +
+
+ + + + diff --git a/roo/src/main/resources/templates/books/showInline.html b/roo/src/main/resources/templates/books/showInline.html new file mode 100644 index 0000000000..9fbc62cf26 --- /dev/null +++ b/roo/src/main/resources/templates/books/showInline.html @@ -0,0 +1,67 @@ + + + + + Show Book - Spring Roo application + + + + + +
+ +
+ + +
+ + +
+
+ + +
+
    +
  • + title + titleValue +
  • +
  • + author + authorValue +
  • +
  • + isbn + isbnValue +
  • +
+
+ +
+ +
+ +
+ + +
+ +
+ + + + + +
+
+ + + + diff --git a/roo/src/main/resources/templates/error.html b/roo/src/main/resources/templates/error.html new file mode 100644 index 0000000000..7559baba22 --- /dev/null +++ b/roo/src/main/resources/templates/error.html @@ -0,0 +1,40 @@ + + + + + Error - Spring Roo application + + + + + +
+

Error Page

+ +
+ + +
+ + +
+ +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/footer.html b/roo/src/main/resources/templates/fragments/footer.html new file mode 100644 index 0000000000..38999c1b75 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/footer.html @@ -0,0 +1,51 @@ + + + + + Footer + + + + + + + diff --git a/roo/src/main/resources/templates/fragments/header.html b/roo/src/main/resources/templates/fragments/header.html new file mode 100644 index 0000000000..8421d6d77f --- /dev/null +++ b/roo/src/main/resources/templates/fragments/header.html @@ -0,0 +1,21 @@ + + + + + Header + + + +
+
+
+

roo

+

Hello, this is your home page.

+
+
+
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/js/datatables-locale.js b/roo/src/main/resources/templates/fragments/js/datatables-locale.js new file mode 100644 index 0000000000..ad1a32955d --- /dev/null +++ b/roo/src/main/resources/templates/fragments/js/datatables-locale.js @@ -0,0 +1,67 @@ +// IIFE - Immediately Invoked Function Expression +(function(translateDatatables) { + + // The global jQuery object is passed as a parameter + translateDatatables(window.jQuery, window, document); + +}(function($, window, document) { + + // The $ is now locally scoped, it won't collide with other libraries + + // Listen for the jQuery ready event on the document + // READY EVENT BEGIN + $(function() { + + // The DOM is ready! + //console.log('The DOM is ready'); + + // Set datatables defaults + $.extend($.fn.dataTable.defaults, { + // multilingual texts definitions, adding some to those already provided + // default by Datatables + 'language': { + 'buttons': { + 'add': /*[[#{label_datatables_add}]]*/ 'Add', + 'delete': /*[[#{label_datatables_delete}]]*/ 'Delete', + 'colvis': /*[[#{label_datatables_columns}]]*/ 'Columns', + 'pageLength': /*[[#{label_datatables_showRows}]]*/ 'Show %d rows' + }, + 'select': { + 'rows': { + _: /*[[#{label_datatables_selectedRows}]]*/ '%d selected rows', + 0: "", + 1: /*[[#{label_datatables_selectedRow}]]*/ '1 selected row' + } + }, + 'decimal': /*[[#{label_datatables_decimal}]]*/ '.', + 'emptyTable': /*[[#{label_datatables_emptyTable}]]*/ 'No data available in table', + 'info': /*[[#{label_datatables_info}]]*/ 'Showing _START_ to _END_ of _TOTAL_ entries', + 'infoEmpty': /*[[#{label_datatables_infoEmpty}]]*/ 'Showing 0 to 0 of 0 entries', + 'infoFiltered': /*[[#{label_datatables_infoFiltered}]]*/ '(filtered from _MAX_ total entries)', + 'infoPostFix': /*[[#{label_datatables_infoPostFix}]]*/ '', + 'thousands': /*[[#{label_datatables_thousands}]]*/ '', + 'lengthMenu': /*[[#{label_datatables_lengthMenu}]]*/ 'Show _MENU_ entries', + 'loadingRecords': /*[[#{label_datatables_loadingRecords}]]*/ 'Loading...', + 'processing': /*[[#{label_datatables_processing}]]*/ 'Processing...', + 'search': /*[[#{label_datatables_search}]]*/ 'Search:', + 'zeroRecords': /*[[#{label_datatables_zeroRecords}]]*/ ' No matching records found', + 'paginate': { + 'first': /*[[#{label_datatables_first}]]*/ 'First', + 'last': /*[[#{label_datatables_last}]]*/ 'Last', + 'next': /*[[#{label_datatables_next}]]*/ 'Next', + 'previous': /*[[#{label_datatables_previous}]]*/ 'Previous' + }, + 'aria': { + 'sortAscending': /*[[#{label_datatables_sortAscending}]]*/ ': activate to sort column ascending', + 'sortDescending': /*[[#{label_datatables_sortDescending}]]*/ ': activate to sort column descending' + } + } + }); + + }); + + // READY EVENT END + //console.log('The DOM may not be ready'); + + // The rest of code goes here! +})); diff --git a/roo/src/main/resources/templates/fragments/js/datatables.html b/roo/src/main/resources/templates/fragments/js/datatables.html new file mode 100644 index 0000000000..5993777eb3 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/js/datatables.html @@ -0,0 +1,78 @@ + + + + + Session info + + + + + +
+ + +
+

Error

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/js/select2.html b/roo/src/main/resources/templates/fragments/js/select2.html new file mode 100644 index 0000000000..ce2c6bd7a4 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/js/select2.html @@ -0,0 +1,16 @@ + + + + +Select2 + + +
+ + + +
+ + diff --git a/roo/src/main/resources/templates/fragments/languages.html b/roo/src/main/resources/templates/fragments/languages.html new file mode 100644 index 0000000000..248f9eaea0 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/languages.html @@ -0,0 +1,33 @@ + + + + + Languages + + + + + + + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/menu.html b/roo/src/main/resources/templates/fragments/menu.html new file mode 100644 index 0000000000..86143276e1 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/menu.html @@ -0,0 +1,107 @@ + + + + + Page menu + + + + + + + + + + diff --git a/roo/src/main/resources/templates/fragments/modal-confirm-delete-batch.html b/roo/src/main/resources/templates/fragments/modal-confirm-delete-batch.html new file mode 100644 index 0000000000..3ce82279ac --- /dev/null +++ b/roo/src/main/resources/templates/fragments/modal-confirm-delete-batch.html @@ -0,0 +1,34 @@ + + + + +Modal + + + +
+
+
+

Going to remove the selected elements

+
+
+ + +
+
+ +
+

Removed selected items

+
+ +
+

Error deleting selected items.

+
+ +
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/modal-confirm-delete.html b/roo/src/main/resources/templates/fragments/modal-confirm-delete.html new file mode 100644 index 0000000000..658c04054f --- /dev/null +++ b/roo/src/main/resources/templates/fragments/modal-confirm-delete.html @@ -0,0 +1,35 @@ + + + + +Modal + + + +
+
+
+

Going to remove the selected + element

+
+
+ + +
+
+ +
+

1 Removed item

+
+ +
+

Error deleting selected item.

+
+ +
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/modal-confirm.html b/roo/src/main/resources/templates/fragments/modal-confirm.html new file mode 100644 index 0000000000..7d0fb8d4f8 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/modal-confirm.html @@ -0,0 +1,32 @@ + + + + +Modal + + + +
+
+
+ +

Going to remove the selected + element

+ +
+
+ 100% Complete +
+
+
+ +
+
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/modal-export-empty-error.html b/roo/src/main/resources/templates/fragments/modal-export-empty-error.html new file mode 100644 index 0000000000..dd84d8fe9e --- /dev/null +++ b/roo/src/main/resources/templates/fragments/modal-export-empty-error.html @@ -0,0 +1,20 @@ + + + + +Modal + + + +
+ +
+

No records found to generate a report.

+
+ +
+ + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/modal.html b/roo/src/main/resources/templates/fragments/modal.html new file mode 100644 index 0000000000..55e13158a4 --- /dev/null +++ b/roo/src/main/resources/templates/fragments/modal.html @@ -0,0 +1,27 @@ + + + + + Modal + + + + + + \ No newline at end of file diff --git a/roo/src/main/resources/templates/fragments/session-links.html b/roo/src/main/resources/templates/fragments/session-links.html new file mode 100644 index 0000000000..786a7a4aec --- /dev/null +++ b/roo/src/main/resources/templates/fragments/session-links.html @@ -0,0 +1,46 @@ + + + + + Session info + + + + + + + + + \ No newline at end of file diff --git a/roo/src/main/resources/templates/index.html b/roo/src/main/resources/templates/index.html new file mode 100644 index 0000000000..e4aac5e9a7 --- /dev/null +++ b/roo/src/main/resources/templates/index.html @@ -0,0 +1,150 @@ + + + + + Welcome - SpringRoo Application + + + + + +
+ +
+ + +
+ + +
+
+ +
+ +
+ +
+

With Roo you can easily build full Java applications in minutes.

+

Spring Roo is a next-generation rapid application development tool for Java developers. + It focuses on higher productivity, stock-standard Java APIs, high usability, avoiding engineering trade-offs and + facilitating easy Roo removal. +

+

Thanks for your interest in Spring Roo!

+
+
+
+ + +
+ + +
+
+
+
+ +
+
+

Doc

+ If you are looking for Reference Documentation you can get it here. +
+
+
+
+ + +
+
+
+
+ +
+
+

Project Page

+ All the info about Spring Roo development. +
+
+
+
+ + +
+
+
+
+ +
+
+

Support

+ If you have any question about the project, + you can check it. +
+
+
+
+ + +
+
+
+
+ +
+
+

Code

+ Known, modify and redistribute the source code. +
+
+
+
+ +
+ + +
+
+ +
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+
+ + + + diff --git a/roo/src/main/resources/templates/layouts/default-layout-no-menu.html b/roo/src/main/resources/templates/layouts/default-layout-no-menu.html new file mode 100644 index 0000000000..40d502800f --- /dev/null +++ b/roo/src/main/resources/templates/layouts/default-layout-no-menu.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + Spring Roo application + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +

Sample static body for direct display of the template

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent + scelerisque neque neque, ac elementum quam dignissim interdum. Phasellus et + placerat elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Praesent scelerisque neque neque, ac elementum quam dignissim interdum. + Phasellus et placerat elit.

+
+ +
+ +
+ + © 2016 Spring Roo (footer for example for direct display of the template) +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + + diff --git a/roo/src/main/resources/templates/layouts/default-layout.html b/roo/src/main/resources/templates/layouts/default-layout.html new file mode 100644 index 0000000000..ba597630d4 --- /dev/null +++ b/roo/src/main/resources/templates/layouts/default-layout.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + Spring Roo application + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +

Sample static body for direct display of the template

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent + scelerisque neque neque, ac elementum quam dignissim interdum. Phasellus et + placerat elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Praesent scelerisque neque neque, ac elementum quam dignissim interdum. + Phasellus et placerat elit.

+
+ +
+ +
+ + © 2016 Spring Roo (footer for example for direct display of the template) +
+ + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + + + + diff --git a/roo/src/main/resources/templates/layouts/default-list-layout.html b/roo/src/main/resources/templates/layouts/default-list-layout.html new file mode 100644 index 0000000000..23f5002241 --- /dev/null +++ b/roo/src/main/resources/templates/layouts/default-list-layout.html @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + Spring Roo application + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +

Sample static body for direct display of the template

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent + scelerisque neque neque, ac elementum quam dignissim interdum. Phasellus et + placerat elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Praesent scelerisque neque neque, ac elementum quam dignissim interdum. + Phasellus et placerat elit.

+
+ +
+ +
+ + © 2016 Spring Roo (footer for example for direct display of the template) +
+ + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + + + + diff --git a/roo/src/main/resources/templates/layouts/home-layout.html b/roo/src/main/resources/templates/layouts/home-layout.html new file mode 100644 index 0000000000..7c1d2f7c5c --- /dev/null +++ b/roo/src/main/resources/templates/layouts/home-layout.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + Spring Roo application + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +

Sample page header for direct display of the template

+
+
+ +
+ +
+ +

Sample static body for direct display of the template

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent + scelerisque neque neque, ac elementum quam dignissim interdum. Phasellus et + placerat elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Praesent scelerisque neque neque, ac elementum quam dignissim interdum. + Phasellus et placerat elit.

+
+ +
+ +
+ + © 2016 Spring Roo (footer for example for direct display of the template) +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + + diff --git a/roo/src/main/resources/templates/login.html b/roo/src/main/resources/templates/login.html new file mode 100644 index 0000000000..627b165049 --- /dev/null +++ b/roo/src/main/resources/templates/login.html @@ -0,0 +1,108 @@ + + + + + Login- Spring Roo application + + + + + +
+ +
+ + +
+ + +
+
+ +
+
+

Login

+
+
+
+
+ Enter your login and password + + + + + + +
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ + + + + +
+
+ + + + diff --git a/roo/src/main/resources/templates/reports/export_default.jrxml b/roo/src/main/resources/templates/reports/export_default.jrxml new file mode 100644 index 0000000000..3540f690de --- /dev/null +++ b/roo/src/main/resources/templates/reports/export_default.jrxml @@ -0,0 +1,59 @@ + + + + + + + + + + <band height="94"> + <frame> + <reportElement mode="Opaque" x="-20" y="-20" width="595" height="92" backcolor="#054571" uuid="96670a12-0a0b-4503-8309-d43c1bd41fa5"/> + <staticText> + <reportElement x="20" y="20" width="234" height="43" forecolor="#FFFFFF" uuid="887580cd-50ec-499d-ba19-3971bf3a5552"/> + <textElement> + <font size="34" isBold="true"/> + </textElement> + <text><![CDATA[Export]]></text> + </staticText> + </frame> + <staticText> + <reportElement x="206" y="74" width="100" height="20" uuid="6efdf519-1cda-447d-bb04-5dfca2ae8aed"/> + <text><![CDATA[]]></text> + </staticText> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/constructordi/SpringRunner.java b/spring-core/src/main/java/com/baeldung/constructordi/SpringRunner.java index 623739f036..bffd35ec59 100644 --- a/spring-core/src/main/java/com/baeldung/constructordi/SpringRunner.java +++ b/spring-core/src/main/java/com/baeldung/constructordi/SpringRunner.java @@ -1,31 +1,31 @@ -package com.baeldung.constructordi; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import com.baeldung.constructordi.domain.Car; - -public class SpringRunner { - public static void main(String[] args) { - Car toyota = getCarFromXml(); - - System.out.println(toyota); - - toyota = getCarFromJavaConfig(); - - System.out.println(toyota); - } - - private static Car getCarFromJavaConfig() { - ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); - - return context.getBean(Car.class); - } - - private static Car getCarFromXml() { - ApplicationContext context = new ClassPathXmlApplicationContext("baeldung.xml"); - - return context.getBean(Car.class); - } -} +package com.baeldung.constructordi; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.baeldung.constructordi.domain.Car; + +public class SpringRunner { + public static void main(String[] args) { + Car toyota = getCarFromXml(); + + System.out.println(toyota); + + toyota = getCarFromJavaConfig(); + + System.out.println(toyota); + } + + private static Car getCarFromJavaConfig() { + ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); + + return context.getBean(Car.class); + } + + private static Car getCarFromXml() { + ApplicationContext context = new ClassPathXmlApplicationContext("constructordi.xml"); + + return context.getBean(Car.class); + } +} diff --git a/spring-core/src/main/java/com/baeldung/constructordi/domain/Car.java b/spring-core/src/main/java/com/baeldung/constructordi/domain/Car.java index 9f68ba5cd9..5c9467fdf4 100644 --- a/spring-core/src/main/java/com/baeldung/constructordi/domain/Car.java +++ b/spring-core/src/main/java/com/baeldung/constructordi/domain/Car.java @@ -1,21 +1,21 @@ -package com.baeldung.constructordi.domain; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class Car { - private Engine engine; - private Transmission transmission; - - @Autowired - public Car(Engine engine, Transmission transmission) { - this.engine = engine; - this.transmission = transmission; - } - - @Override - public String toString() { - return String.format("Engine: %s Transmission: %s", engine, transmission); - } -} +package com.baeldung.constructordi.domain; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class Car { + private Engine engine; + private Transmission transmission; + + @Autowired + public Car(Engine engine, Transmission transmission) { + this.engine = engine; + this.transmission = transmission; + } + + @Override + public String toString() { + return String.format("Engine: %s Transmission: %s", engine, transmission); + } +} diff --git a/spring-core/src/main/java/com/baeldung/setterdi/Config.java b/spring-core/src/main/java/com/baeldung/setterdi/Config.java new file mode 100644 index 0000000000..68c1ae12a2 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/Config.java @@ -0,0 +1,35 @@ +package com.baeldung.setterdi; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import com.baeldung.setterdi.domain.Engine; +import com.baeldung.setterdi.domain.Trailer; +import com.baeldung.setterdi.domain.Transmission; + +@Configuration +@ComponentScan("com.baeldung.setterdi") +public class Config { + + @Bean + public Engine engine() { + Engine engine = new Engine(); + engine.setType("v8"); + engine.setVolume(5); + return engine; + } + + @Bean + public Transmission transmission() { + Transmission transmission = new Transmission(); + transmission.setType("sliding"); + return transmission; + } + + @Bean + public Trailer trailer() { + Trailer trailer = new Trailer(); + return trailer; + } +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/setterdi/SpringRunner.java b/spring-core/src/main/java/com/baeldung/setterdi/SpringRunner.java new file mode 100644 index 0000000000..bc92b79e8a --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/SpringRunner.java @@ -0,0 +1,33 @@ +package com.baeldung.setterdi; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.baeldung.setterdi.Config; +import com.baeldung.setterdi.domain.Car; + +public class SpringRunner { + public static void main(String[] args) { + Car toyota = getCarFromXml(); + + System.out.println(toyota); + + toyota = getCarFromJavaConfig(); + + System.out.println(toyota); + + } + + private static Car getCarFromJavaConfig() { + ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); + + return context.getBean(Car.class); + } + + private static Car getCarFromXml() { + ApplicationContext context = new ClassPathXmlApplicationContext("setterdi.xml"); + + return context.getBean(Car.class); + } +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/setterdi/domain/Car.java b/spring-core/src/main/java/com/baeldung/setterdi/domain/Car.java new file mode 100644 index 0000000000..749ff3984a --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/domain/Car.java @@ -0,0 +1,34 @@ +package com.baeldung.setterdi.domain; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class Car { + private Engine engine; + private Transmission transmission; + private Trailer trailer; + + public Car() { + } + + @Autowired + public void setEngine(Engine engine) { + this.engine = engine; + } + + @Autowired + public void setTransmission(Transmission transmission) { + this.transmission = transmission; + } + + @Autowired + public void setTrailer(Trailer trailer) { + this.trailer = trailer; + } + + @Override + public String toString() { + return String.format("Engine: %s Transmission: %s Trailer: %s", engine, transmission, trailer); + } +} diff --git a/spring-core/src/main/java/com/baeldung/setterdi/domain/Engine.java b/spring-core/src/main/java/com/baeldung/setterdi/domain/Engine.java new file mode 100644 index 0000000000..50c247cacf --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/domain/Engine.java @@ -0,0 +1,22 @@ +package com.baeldung.setterdi.domain; + +public class Engine { + private String type; + private int volume; + + public Engine() { + } + + public void setType(String type) { + this.type = type; + } + + public void setVolume(int volume) { + this.volume = volume; + } + + @Override + public String toString() { + return String.format("%s %d", type, volume); + } +} \ No newline at end of file diff --git a/spring-core/src/main/java/com/baeldung/setterdi/domain/Trailer.java b/spring-core/src/main/java/com/baeldung/setterdi/domain/Trailer.java new file mode 100644 index 0000000000..616732309e --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/domain/Trailer.java @@ -0,0 +1,11 @@ +package com.baeldung.setterdi.domain; + +public class Trailer { + public Trailer() { + } + + @Override + public String toString() { + return "Trailer"; + } +} diff --git a/spring-core/src/main/java/com/baeldung/setterdi/domain/Transmission.java b/spring-core/src/main/java/com/baeldung/setterdi/domain/Transmission.java new file mode 100644 index 0000000000..18b62afdc1 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/setterdi/domain/Transmission.java @@ -0,0 +1,17 @@ +package com.baeldung.setterdi.domain; + +public class Transmission { + private String type; + + public Transmission() { + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return String.format("%s", type); + } +} diff --git a/spring-core/src/main/resources/constructordi.xml b/spring-core/src/main/resources/constructordi.xml new file mode 100644 index 0000000000..231e72adcb --- /dev/null +++ b/spring-core/src/main/resources/constructordi.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/spring-core/src/main/resources/setterdi.xml b/spring-core/src/main/resources/setterdi.xml new file mode 100644 index 0000000000..8b7f0d41e7 --- /dev/null +++ b/spring-core/src/main/resources/setterdi.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + From fd8e872feb9756f80125f0e4893b2ccf77b3494e Mon Sep 17 00:00:00 2001 From: Himanshu Bhardwaj Date: Thu, 6 Apr 2017 14:14:28 +0530 Subject: [PATCH 261/291] [BAEL-752] Cucumber with Scenario Outline (#1583) * [BAEL-752] Cucumbr with Scenario Outline * Corrected indentation * Applied more formatting guidelines. * Java standard used for method names --- cucumber/pom.xml | 93 +++++++++++++++++++ .../cucumber/calculator/Calculator.java | 7 ++ .../calculator/CalculatorRunSteps.java | 38 ++++++++ .../cucumber/calculator/CalculatorTest.java | 15 +++ .../calculator-scenario-outline.feature | 16 ++++ .../resources/features/calculator.feature | 24 +++++ cucumber/src/test/resources/logback-test.xml | 13 +++ pom.xml | 1 + 8 files changed, 207 insertions(+) create mode 100644 cucumber/pom.xml create mode 100644 cucumber/src/main/java/com/baeldung/cucumber/calculator/Calculator.java create mode 100644 cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorRunSteps.java create mode 100644 cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorTest.java create mode 100644 cucumber/src/test/resources/features/calculator-scenario-outline.feature create mode 100644 cucumber/src/test/resources/features/calculator.feature create mode 100644 cucumber/src/test/resources/logback-test.xml diff --git a/cucumber/pom.xml b/cucumber/pom.xml new file mode 100644 index 0000000000..77d04f96c2 --- /dev/null +++ b/cucumber/pom.xml @@ -0,0 +1,93 @@ + + 4.0.0 + com.baeldung + cucumber + 1.0.0-SNAPSHOT + jar + + + 1.8 + 1.8 + UTF-8 + 3.5.1 + 1.7.21 + 1.1.7 + 4.12 + 1.3 + 1.2.5 + 2.19.1 + + + + + + + + info.cukes + cucumber-junit + ${cucumber.version} + test + + + + info.cukes + cucumber-java + ${cucumber.version} + test + + + + org.hamcrest + hamcrest-library + ${hamcrest.library.version} + test + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + ch.qos.logback + logback-classic + ${logback.version} + + + + ch.qos.logback + logback-core + ${logback.version} + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + true + true + ${java.source.version} + ${java.target.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.plugin.version} + + + **/CalculatorTest.java + + + + + + + \ No newline at end of file diff --git a/cucumber/src/main/java/com/baeldung/cucumber/calculator/Calculator.java b/cucumber/src/main/java/com/baeldung/cucumber/calculator/Calculator.java new file mode 100644 index 0000000000..fd4a3bad7b --- /dev/null +++ b/cucumber/src/main/java/com/baeldung/cucumber/calculator/Calculator.java @@ -0,0 +1,7 @@ +package com.baeldung.cucumber.calculator; + +public class Calculator { + public int add(int a, int b) { + return a + b; + } +} diff --git a/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorRunSteps.java b/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorRunSteps.java new file mode 100644 index 0000000000..9c0e920a8d --- /dev/null +++ b/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorRunSteps.java @@ -0,0 +1,38 @@ +package com.baeldung.cucumber.calculator; + +import org.hamcrest.Matchers; +import org.junit.Assert; + +import cucumber.api.java.Before; +import cucumber.api.java.en.Given; +import cucumber.api.java.en.Then; +import cucumber.api.java.en.When; + +public class CalculatorRunSteps { + + private int total; + + private Calculator calculator; + + @Before + private void init() { + total = -999; + + } + + @Given("^I have a calculator$") + public void initializeCalculator() throws Throwable { + calculator = new Calculator(); + } + + @When("^I add (-?\\d+) and (-?\\d+)$") + public void testAdd(int num1, int num2) throws Throwable { + total = calculator.add(num1, num2); + } + + @Then("^the result should be (-?\\d+)$") + public void validateResult(int result) throws Throwable { + Assert.assertThat(total, Matchers.equalTo(result)); + } + +} diff --git a/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorTest.java b/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorTest.java new file mode 100644 index 0000000000..6bbbca60d2 --- /dev/null +++ b/cucumber/src/test/java/com/baeldung/cucumber/calculator/CalculatorTest.java @@ -0,0 +1,15 @@ +package com.baeldung.cucumber.calculator; + +import org.junit.runner.RunWith; + +import cucumber.api.CucumberOptions; +import cucumber.api.junit.Cucumber; + +@RunWith(Cucumber.class) +@CucumberOptions( + features={"classpath:features/calculator.feature", "classpath:features/calculator-scenario-outline.feature"} + , plugin = { "pretty", "json:target/reports/json/calculator.json" } + , glue = {"com.baeldung.cucumber.calculator"} +) +public class CalculatorTest { +} diff --git a/cucumber/src/test/resources/features/calculator-scenario-outline.feature b/cucumber/src/test/resources/features/calculator-scenario-outline.feature new file mode 100644 index 0000000000..7437dbf5f9 --- /dev/null +++ b/cucumber/src/test/resources/features/calculator-scenario-outline.feature @@ -0,0 +1,16 @@ +Feature: Calculator + As a user + I want to use a calculator to add numbers + So that I don't need to add myself + + Scenario Outline: Add two numbers & + Given I have a calculator + When I add and + Then the result should be + + Examples: + | num1 | num2 | total | + | -2 | 3 | 1 | + | 10 | 15 | 25 | + | 99 | -99 | 0 | + | -1 | -10 | -11 | \ No newline at end of file diff --git a/cucumber/src/test/resources/features/calculator.feature b/cucumber/src/test/resources/features/calculator.feature new file mode 100644 index 0000000000..eaf05cb6ca --- /dev/null +++ b/cucumber/src/test/resources/features/calculator.feature @@ -0,0 +1,24 @@ +Feature: Calculator + As a user + I want to use a calculator to add numbers + So that I don't need to add myself + + Scenario: Add two numbers -2 & 3 + Given I have a calculator + When I add -2 and 3 + Then the result should be 1 + + Scenario: Add two numbers 10 & 15 + Given I have a calculator + When I add 10 and 15 + Then the result should be 25 + + Scenario: Add two numbers 99 & -99 + Given I have a calculator + When I add 99 and -99 + Then the result should be 0 + + Scenario: Add two numbers -1 & -10 + Given I have a calculator + When I add -1 and -10 + Then the result should be -11 \ No newline at end of file diff --git a/cucumber/src/test/resources/logback-test.xml b/cucumber/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..e980d88693 --- /dev/null +++ b/cucumber/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%ex + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a582ff3e70..0b569b49fd 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,7 @@ rabbitmq vertx spring-data-gemfire + cucumber From 22dda8c2be6861c56a47861137fbbbb067a72b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20G=C3=B3mez?= Date: Fri, 7 Apr 2017 00:09:53 -0600 Subject: [PATCH 262/291] Fix/readme update (#1602) * Add project for hibernate immutable article Add Event entity Add hibernate configuration file Add hibernateutil for configuration Add test to match snippets from article * Update Readme for core-java and spring-hibernate4 * Updating repo --- core-java/README.md | 1 + spring-hibernate4/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/core-java/README.md b/core-java/README.md index 0861ee7c5e..096ff51df6 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -11,6 +11,7 @@ - [Converting between a List and a Set in Java](http://www.baeldung.com/convert-list-to-set-and-set-to-list) - [Convert a Map to an Array, List or Set in Java](http://www.baeldung.com/convert-map-values-to-array-list-set) - [Java – Write to File](http://www.baeldung.com/java-write-to-file) +- [Java - Convert File to InputStream] (http://www.baeldung.com/convert-file-to-input-stream) - [Java Scanner](http://www.baeldung.com/java-scanner) - [Java Timer](http://www.baeldung.com/java-timer-and-timertask) - [Java – Byte Array to Writer](http://www.baeldung.com/java-convert-byte-array-to-writer) diff --git a/spring-hibernate4/README.md b/spring-hibernate4/README.md index 02888c4ad0..08cfe2b538 100644 --- a/spring-hibernate4/README.md +++ b/spring-hibernate4/README.md @@ -13,6 +13,7 @@ - [Eager/Lazy Loading In Hibernate](http://www.baeldung.com/hibernate-lazy-eager-loading) - [Hibernate Criteria Queries](http://www.baeldung.com/hibernate-criteria-queries) - [Hibernate One to Many Annotation Tutorial](http://www.baeldung.com/hibernate-one-to-many) +- [Guide to @Immutable Annotation in Hibernate](http://www.baeldung.com/hibernate-immutable) ### Quick Start From 69965db18733170361a7eda5aec7c8a02f2e992c Mon Sep 17 00:00:00 2001 From: Tehreem Date: Fri, 7 Apr 2017 12:47:33 +0500 Subject: [PATCH 263/291] Spring Cloud Zookeeper (#1399) * Spring Cloud Zookeeper * Spring Cloud Zookeeper Updated --- spring-cloud/pom.xml | 1 + .../spring-cloud-zookeeper/Greeting/pom.xml | 78 +++++++++++++++++++ .../cloud/greeting/GreetingApplication.java | 27 +++++++ .../cloud/greeting/GreetingController.java | 33 ++++++++ .../cloud/greeting/HelloWorldClient.java | 49 ++++++++++++ .../src/main/resources/application.yml | 11 +++ .../resources/templates/greeting-view.html | 9 +++ .../spring-cloud-zookeeper/HelloWorld/pom.xml | 51 ++++++++++++ .../helloworld/HelloWorldApplication.java | 18 +++++ .../helloworld/HelloWorldController.java | 21 +++++ .../src/main/resources/application.yml | 16 ++++ spring-cloud/spring-cloud-zookeeper/pom.xml | 15 ++++ 12 files changed, 329 insertions(+) create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/application.yml create mode 100644 spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/templates/greeting-view.html create mode 100644 spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml create mode 100644 spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldApplication.java create mode 100644 spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java create mode 100644 spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/resources/application.yml create mode 100644 spring-cloud/spring-cloud-zookeeper/pom.xml diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index 5b5b006d01..6d53b24647 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -13,6 +13,7 @@ spring-cloud-bootstrap spring-cloud-ribbon-client spring-cloud-rest + spring-cloud-zookeeper pom diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml b/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml new file mode 100644 index 0000000000..4d19741210 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + spring-cloud-zookeeper + 1.0.0-SNAPSHOT + + Greeting + jar + + + org.springframework.boot + spring-boot-starter + 1.5.2.RELEASE + + + org.springframework + spring-web + 4.3.7.RELEASE + + + org.springframework.cloud + spring-cloud-starter-zookeeper-discovery + 1.0.3.RELEASE + + + org.springframework.boot + spring-boot-starter-actuator + 1.5.2.RELEASE + + + org.springframework.cloud + spring-cloud-starter-feign + 1.2.5.RELEASE + + + org.springframework.boot + spring-boot-starter-thymeleaf + 1.5.2.RELEASE + + + junit + junit + 4.12 + test + + + org.hamcrest + hamcrest-core + 1.3 + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + Brixton.SR7 + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + Greeting + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java new file mode 100644 index 0000000000..e8beebeadf --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.spring.cloud.greeting; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.feign.EnableFeignClients; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +@EnableDiscoveryClient +public class GreetingApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingApplication.class, args); + } + +} diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java new file mode 100644 index 0000000000..d701a2c762 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.spring.cloud.greeting; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.netflix.feign.EnableFeignClients; +import org.springframework.stereotype.Controller; + +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@Controller +public class GreetingController { + + @Autowired + private HelloWorldClient helloWorldClient; + + @RequestMapping(value = "/get-greeting", method = RequestMethod.GET) + + public String greeting(Model model) { + + model.addAttribute("greeting", helloWorldClient.HelloWorld()); + return "greeting-view"; + + } + +} diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java new file mode 100644 index 0000000000..d2b91ca715 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java @@ -0,0 +1,49 @@ +package com.baeldung.spring.cloud.greeting; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.feign.EnableFeignClients; +import org.springframework.cloud.netflix.feign.FeignClient; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * This class provides operations on the Validation service. + * + *

+ * When booting up, Spring will try and find a service named "Validation" (see + * the FeignClient below) under the available ZooKeeper instance. + *

+ * + */ +@Configuration +@EnableFeignClients +@EnableDiscoveryClient +public class HelloWorldClient { + + @Autowired + private TheClient theClient; + + @FeignClient(name = "HelloWorld") + interface TheClient { + + @RequestMapping(path = "/helloworld", method = RequestMethod.GET) + @ResponseBody + String HelloWorld(); + } + + /** + * Initiate call to Validation. + * + * @param name + * @return the response + */ + public String HelloWorld() { + return theClient.HelloWorld(); + } + +} diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/application.yml b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/application.yml new file mode 100644 index 0000000000..6140f6ab2f --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/application.yml @@ -0,0 +1,11 @@ +spring: + application: + name: Greeting + cloud: + zookeeper: + connect-string: localhost:2181 +server: + port: 8083 +logging: + level: + org.apache.zookeeper.ClientCnxn: WARN \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/templates/greeting-view.html b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/templates/greeting-view.html new file mode 100644 index 0000000000..42cdadb487 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/resources/templates/greeting-view.html @@ -0,0 +1,9 @@ + + + + Greeting Page + + +

+ + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml b/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml new file mode 100644 index 0000000000..1c829a50df --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + spring-cloud-zookeeper + 1.0.0-SNAPSHOT + + HelloWorld + jar + + + org.springframework.boot + spring-boot-starter + 1.5.2.RELEASE + + + org.springframework + spring-web + 4.3.7.RELEASE + + + org.springframework.cloud + spring-cloud-starter-zookeeper-discovery + 1.0.3.RELEASE + + + + + + + org.springframework.cloud + spring-cloud-dependencies + Brixton.SR7 + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + HelloWorld + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldApplication.java b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldApplication.java new file mode 100644 index 0000000000..8b35071516 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldApplication.java @@ -0,0 +1,18 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.spring.cloud.helloworld; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +public class HelloWorldApplication { + public static void main(String[] args) { + SpringApplication.run(HelloWorldApplication.class, args); + } +} diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java new file mode 100644 index 0000000000..d5ea84de19 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java @@ -0,0 +1,21 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.baeldung.spring.cloud.helloworld; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloWorldController { + + @RequestMapping(path = "/helloworld", method = RequestMethod.GET) + public String HelloWorld() { + return "Hello World!"; + } + +} diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/resources/application.yml b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/resources/application.yml new file mode 100644 index 0000000000..550165a762 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/resources/application.yml @@ -0,0 +1,16 @@ +spring: + application: + name: HelloWorld + cloud: + zookeeper: + connect-string: localhost:2181 + discovery: + enabled: true +server: + port: 8081 +endpoints: + restart: + enabled: true +logging: + level: + org.apache.zookeeper.ClientCnxn: WARN \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zookeeper/pom.xml b/spring-cloud/spring-cloud-zookeeper/pom.xml new file mode 100644 index 0000000000..8406813161 --- /dev/null +++ b/spring-cloud/spring-cloud-zookeeper/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + spring-cloud + 1.0.0-SNAPSHOT + + spring-cloud-zookeeper + pom + + Greeting + HelloWorld + + \ No newline at end of file From d87e0663fc7a9f3aedd20d8b465545cf0e65abe8 Mon Sep 17 00:00:00 2001 From: Mohamed Sanaulla Date: Fri, 7 Apr 2017 17:31:39 +0300 Subject: [PATCH 264/291] incorporate review comments for BAEL-747 (#1603) --- .../primechecker/BigIntegerPrimeChecker.java | 4 ++-- .../primechecker/BruteForcePrimeChecker.java | 9 ++++++--- .../primechecker/OptimisedPrimeChecker.java | 9 +++++---- .../algorithms/primechecker/PrimeChecker.java | 4 ++-- .../algorithms/primechecker/PrimesPrimeChecker.java | 4 ++-- .../primechecker/BigIntegerPrimeCheckerTest.java | 12 +++++++----- .../primechecker/OptimisedPrimeCheckerTest.java | 2 +- .../primechecker/PrimesPrimeCheckerTest.java | 2 +- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeChecker.java b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeChecker.java index bd4708b661..752e659fa3 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeChecker.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeChecker.java @@ -2,10 +2,10 @@ package com.baeldung.algorithms.primechecker; import java.math.BigInteger; -public class BigIntegerPrimeChecker implements PrimeChecker{ +public class BigIntegerPrimeChecker implements PrimeChecker{ @Override - public boolean isPrime(int number) { + public boolean isPrime(Long number) { BigInteger bigInt = BigInteger.valueOf(number); return bigInt.isProbablePrime(100); } diff --git a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BruteForcePrimeChecker.java b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BruteForcePrimeChecker.java index 0dfcfa1505..47ffb3e224 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BruteForcePrimeChecker.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/BruteForcePrimeChecker.java @@ -1,12 +1,15 @@ package com.baeldung.algorithms.primechecker; import java.util.stream.IntStream; +import java.util.stream.LongStream; -public class BruteForcePrimeChecker implements PrimeChecker{ +public class BruteForcePrimeChecker implements PrimeChecker{ @Override - public boolean isPrime(int number) { - return IntStream.range(2, number).noneMatch(n -> (number % n == 0)); + public boolean isPrime(Integer number) { + + return number > 2 ? IntStream.range(2, number) + .noneMatch(n -> (number % n == 0)) : false; } diff --git a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/OptimisedPrimeChecker.java b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/OptimisedPrimeChecker.java index f7e3e09be0..06ae4acc7f 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/OptimisedPrimeChecker.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/OptimisedPrimeChecker.java @@ -1,13 +1,14 @@ package com.baeldung.algorithms.primechecker; import java.util.stream.IntStream; +import java.util.stream.LongStream; -public class OptimisedPrimeChecker implements PrimeChecker{ +public class OptimisedPrimeChecker implements PrimeChecker{ @Override - public boolean isPrime(int number) { - return IntStream.range(2, (int)Math.sqrt(number) + 1) - .noneMatch(n -> (number % n == 0)); + public boolean isPrime(Integer number) { + return number > 2 ? IntStream.rangeClosed(2, (int) Math.sqrt(number)) + .noneMatch(n -> (number % n == 0)) : false; } diff --git a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimeChecker.java b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimeChecker.java index f31af1ca4f..5f7a15a939 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimeChecker.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimeChecker.java @@ -1,6 +1,6 @@ package com.baeldung.algorithms.primechecker; -public interface PrimeChecker { +public interface PrimeChecker { - public boolean isPrime( int number ); + public boolean isPrime( T number ); } diff --git a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimesPrimeChecker.java b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimesPrimeChecker.java index ee66d5d2ab..08b095cb79 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimesPrimeChecker.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/primechecker/PrimesPrimeChecker.java @@ -2,10 +2,10 @@ package com.baeldung.algorithms.primechecker; import org.apache.commons.math3.primes.Primes; -public class PrimesPrimeChecker implements PrimeChecker{ +public class PrimesPrimeChecker implements PrimeChecker{ @Override - public boolean isPrime(int number) { + public boolean isPrime(Integer number) { return Primes.isPrime(number); } diff --git a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeCheckerTest.java b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeCheckerTest.java index 95eb85749d..8980397c68 100644 --- a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeCheckerTest.java +++ b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/BigIntegerPrimeCheckerTest.java @@ -9,18 +9,20 @@ import com.baeldung.algorithms.primechecker.PrimeChecker; public class BigIntegerPrimeCheckerTest { - PrimeChecker primeChecker = new BigIntegerPrimeChecker(); + BigIntegerPrimeChecker primeChecker = new BigIntegerPrimeChecker(); @Test public void givenPrimeNumber_whenCheckIsPrime_thenTrue(){ - assertTrue(primeChecker.isPrime(13)); - assertTrue(primeChecker.isPrime(1009)); + assertTrue(primeChecker.isPrime(13l)); + assertTrue(primeChecker.isPrime(1009L)); + assertTrue(primeChecker.isPrime(74207281L)); } @Test public void givenNonPrimeNumber_whenCheckIsPrime_thenFalse(){ - assertTrue(!primeChecker.isPrime(50)); - assertTrue(!primeChecker.isPrime(1001)); + assertTrue(!primeChecker.isPrime(50L)); + assertTrue(!primeChecker.isPrime(1001L)); + assertTrue(!primeChecker.isPrime(74207282L)); } } diff --git a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/OptimisedPrimeCheckerTest.java b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/OptimisedPrimeCheckerTest.java index 21ad55467f..64ecae7cc3 100644 --- a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/OptimisedPrimeCheckerTest.java +++ b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/OptimisedPrimeCheckerTest.java @@ -9,7 +9,7 @@ import com.baeldung.algorithms.primechecker.PrimeChecker; public class OptimisedPrimeCheckerTest { - PrimeChecker primeChecker = new OptimisedPrimeChecker(); + OptimisedPrimeChecker primeChecker = new OptimisedPrimeChecker(); @Test public void givenPrimeNumber_whenCheckIsPrime_thenTrue(){ diff --git a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/PrimesPrimeCheckerTest.java b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/PrimesPrimeCheckerTest.java index 63de593b44..cb294d6643 100644 --- a/algorithms/src/test/java/com/baeldung/algorithms/primechecker/PrimesPrimeCheckerTest.java +++ b/algorithms/src/test/java/com/baeldung/algorithms/primechecker/PrimesPrimeCheckerTest.java @@ -8,7 +8,7 @@ import com.baeldung.algorithms.primechecker.PrimeChecker; import com.baeldung.algorithms.primechecker.PrimesPrimeChecker; public class PrimesPrimeCheckerTest { - PrimeChecker primeChecker = new PrimesPrimeChecker(); + PrimesPrimeChecker primeChecker = new PrimesPrimeChecker(); @Test public void givenPrimeNumber_whenCheckIsPrime_thenTrue() { From 7ab1e373569abb431e4127760b70fa08de1af127 Mon Sep 17 00:00:00 2001 From: Abhinab Kanrar Date: Fri, 7 Apr 2017 20:03:10 +0530 Subject: [PATCH 265/291] cusstom token (#1588) * rest with spark java * 4 * Update Application.java * indentation changes * spring @requestmapping shortcuts * removing spring requestmapping and pushing spring-mvc-java * Joining/Splitting Strings with Java and Stream API * adding more join/split functionality * changing package name * testcase change * adding webutils * adding testcase for WebUtils and ServletRequestUtils * adding testcase * spring-security-stormpath * adding ratpack module * adding pom.xml * adding following modules with updated testcase : DB, Filter, Json * adding spring-boot custom banner tutorial * changing banner format in plain text * Delete banner.txt~ * Delete b.txt~ * CORS in JAX-RS * ratpack with google guice * adding factory instance example * quick-guide-to-the-java-stringtokenizer * Update Application.java * Delete MovieCrudService.java~ * token customization * Update Application.java * adding csv test * adding csv test * Update Application.java * adding collection module --- .../baeldung/stringtokenizer/Application.java | 41 ++++++++++++++++--- core-java/src/main/resources/data.csv | 3 ++ .../stringtokenizer/ApplicationTest.java | 33 +++++++++++---- 3 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 core-java/src/main/resources/data.csv diff --git a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java index caa7ef06da..3fc169f1f7 100644 --- a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java +++ b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java @@ -1,6 +1,10 @@ package com.baeldung.stringtokenizer; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.StringTokenizer; @@ -8,14 +12,41 @@ public class Application { public List getTokens(String str) { List tokens = new ArrayList(); -// StringTokenizer tokenizer = new StringTokenizer( str ); - StringTokenizer tokenizer = new StringTokenizer( str , "," ); -// StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); + // StringTokenizer tokenizer = new StringTokenizer( str ); + StringTokenizer tokenizer = new StringTokenizer(str, ","); + // StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); while (tokenizer.hasMoreElements()) { - tokens.add( tokenizer.nextToken() ); -// tokens.add( tokenizer.nextToken( "," ) ); + tokens.add(tokenizer.nextToken()); + // tokens.add( tokenizer.nextToken("e") ); + } + int tokenLength = tokens.size(); + return tokens; + } + + public List getTokensWithCollection( String str ) { + StringTokenizer tokenizer = new StringTokenizer(str, ","); + List tokens = new ArrayList(); + Collections.list(tokenizer).forEach(token -> tokens.add((String) token)); + return tokens; + } + + public List getTokensFromFile(String path, String delim) { + List tokens = new ArrayList(); + String currLine = ""; + StringTokenizer tokenizer; + try (BufferedReader br = new BufferedReader( + new InputStreamReader(Application.class.getResourceAsStream("/" + path)))) { + while ((currLine = br.readLine()) != null) { + tokenizer = new StringTokenizer(currLine, delim); + while (tokenizer.hasMoreElements()) { + tokens.add(tokenizer.nextToken()); + } + } + } catch (IOException e) { + e.printStackTrace(); } return tokens; } + } diff --git a/core-java/src/main/resources/data.csv b/core-java/src/main/resources/data.csv new file mode 100644 index 0000000000..ec4ac10443 --- /dev/null +++ b/core-java/src/main/resources/data.csv @@ -0,0 +1,3 @@ +1|IND|India +2|MY|Malaysia +3|AU|Australia diff --git a/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java b/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java index 5e3df5b303..5d475d2fbb 100644 --- a/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java +++ b/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java @@ -11,20 +11,37 @@ import static org.junit.Assert.assertEquals; public class ApplicationTest { Application application = new Application(); - List expectedTokens = new ArrayList(); - + List expectedTokensForString = new ArrayList(); + List expectedTokensForFile = new ArrayList(); + @Before public void init() { - expectedTokens.add( "Welcome" ); - expectedTokens.add( "to" ); - expectedTokens.add( "baeldung.com" ); + expectedTokensForString.add("Welcome"); + expectedTokensForString.add("to"); + expectedTokensForString.add("baeldung.com"); + + expectedTokensForFile.add("1"); + expectedTokensForFile.add("IND"); + expectedTokensForFile.add("India"); + expectedTokensForFile.add("2"); + expectedTokensForFile.add("MY"); + expectedTokensForFile.add("Malaysia"); + expectedTokensForFile.add("3"); + expectedTokensForFile.add("AU"); + expectedTokensForFile.add("Australia"); } - + @Test public void givenString_thenGetListOfString() { String str = "Welcome,to,baeldung.com"; List actualTokens = application.getTokens(str); - assertEquals(expectedTokens, actualTokens); + assertEquals(expectedTokensForString, actualTokens); } - + + @Test + public void givenFile_thenGetListOfString() { + List actualTokens = application.getTokensFromFile("data.csv", "|"); + assertEquals(expectedTokensForFile, actualTokens); + } + } From e7d81e6e9829f8b6160278a9a4f715348d8de014 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 7 Apr 2017 16:56:35 +0200 Subject: [PATCH 266/291] Optimize build (#1604) --- apache-fop/pom.xml | 2 ++ pom.xml | 2 ++ querydsl/pom.xml | 2 ++ resteasy/bin/pom.xml | 2 ++ rxjava/pom.xml | 2 ++ spring-5/pom.xml | 2 ++ spring-akka/pom.xml | 2 ++ spring-cloud-data-flow/data-flow-shell/pom.xml | 2 ++ .../spring-cloud-rest-discovery-server/pom.xml | 2 ++ spring-jersey/pom.xml | 2 ++ spring-mvc-velocity/pom.xml | 3 ++- spring-thymeleaf/pom.xml | 2 ++ spring-userservice/pom.xml | 3 +++ 13 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apache-fop/pom.xml b/apache-fop/pom.xml index 6f89497a7d..6337fe002c 100644 --- a/apache-fop/pom.xml +++ b/apache-fop/pom.xml @@ -140,6 +140,8 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/pom.xml b/pom.xml index 0b569b49fd..b21d656772 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LongRunningUnitTest.java diff --git a/querydsl/pom.xml b/querydsl/pom.xml index b0a07fb3ff..1335d0f1fd 100644 --- a/querydsl/pom.xml +++ b/querydsl/pom.xml @@ -181,6 +181,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/resteasy/bin/pom.xml b/resteasy/bin/pom.xml index f0bd8298f5..1116c0f01a 100644 --- a/resteasy/bin/pom.xml +++ b/resteasy/bin/pom.xml @@ -32,6 +32,8 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/rxjava/pom.xml b/rxjava/pom.xml index 4172187b03..3313713b9b 100644 --- a/rxjava/pom.xml +++ b/rxjava/pom.xml @@ -21,6 +21,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LongRunningUnitTest.java diff --git a/spring-5/pom.xml b/spring-5/pom.xml index f116ed73c0..2c96bae9bc 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -80,6 +80,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-akka/pom.xml b/spring-akka/pom.xml index 1a273b0fed..5965213e65 100644 --- a/spring-akka/pom.xml +++ b/spring-akka/pom.xml @@ -70,6 +70,8 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-cloud-data-flow/data-flow-shell/pom.xml b/spring-cloud-data-flow/data-flow-shell/pom.xml index d3bd297152..350f199d4b 100644 --- a/spring-cloud-data-flow/data-flow-shell/pom.xml +++ b/spring-cloud-data-flow/data-flow-shell/pom.xml @@ -68,6 +68,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/pom.xml b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/pom.xml index d9d08079b7..d9ef26280b 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/pom.xml +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/pom.xml @@ -76,6 +76,8 @@ org.apache.maven.plugins maven-surefire-plugin + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-jersey/pom.xml b/spring-jersey/pom.xml index 41ebb9a6b5..e6c8ea6ef5 100644 --- a/spring-jersey/pom.xml +++ b/spring-jersey/pom.xml @@ -45,6 +45,8 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-mvc-velocity/pom.xml b/spring-mvc-velocity/pom.xml index 31f2d19375..0a9b3a016e 100644 --- a/spring-mvc-velocity/pom.xml +++ b/spring-mvc-velocity/pom.xml @@ -136,8 +136,9 @@ org.apache.maven.plugins maven-surefire-plugin - ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java diff --git a/spring-thymeleaf/pom.xml b/spring-thymeleaf/pom.xml index f5dfc9931e..be443e15df 100644 --- a/spring-thymeleaf/pom.xml +++ b/spring-thymeleaf/pom.xml @@ -176,6 +176,8 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true **/*IntegrationTest.java **/*LiveTest.java diff --git a/spring-userservice/pom.xml b/spring-userservice/pom.xml index c0099173ee..0f3ed96c4e 100644 --- a/spring-userservice/pom.xml +++ b/spring-userservice/pom.xml @@ -239,6 +239,9 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + 3 + true + **/*IntegrationTest.java From 196ea6b5f77c554fd00a21a5cb5bde3607929dc2 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Fri, 7 Apr 2017 18:15:19 +0200 Subject: [PATCH 267/291] Refactor Tokenizer (#1605) --- .../baeldung/stringtokenizer/Application.java | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java index 3fc169f1f7..4560e40697 100644 --- a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java +++ b/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java @@ -7,46 +7,46 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; +import java.util.stream.Collectors; public class Application { - public List getTokens(String str) { - List tokens = new ArrayList(); - // StringTokenizer tokenizer = new StringTokenizer( str ); - StringTokenizer tokenizer = new StringTokenizer(str, ","); - // StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); - while (tokenizer.hasMoreElements()) { - tokens.add(tokenizer.nextToken()); - // tokens.add( tokenizer.nextToken("e") ); - } - int tokenLength = tokens.size(); - return tokens; - } - - public List getTokensWithCollection( String str ) { - StringTokenizer tokenizer = new StringTokenizer(str, ","); - List tokens = new ArrayList(); - Collections.list(tokenizer).forEach(token -> tokens.add((String) token)); - return tokens; - } - - public List getTokensFromFile(String path, String delim) { - List tokens = new ArrayList(); - String currLine = ""; - StringTokenizer tokenizer; - try (BufferedReader br = new BufferedReader( - new InputStreamReader(Application.class.getResourceAsStream("/" + path)))) { - while ((currLine = br.readLine()) != null) { - tokenizer = new StringTokenizer(currLine, delim); - while (tokenizer.hasMoreElements()) { - tokens.add(tokenizer.nextToken()); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - return tokens; - } - + public List getTokens(String str) { + List tokens = new ArrayList(); + // StringTokenizer tokenizer = new StringTokenizer( str ); + StringTokenizer tokenizer = new StringTokenizer(str, ","); + // StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); + while (tokenizer.hasMoreElements()) { + tokens.add(tokenizer.nextToken()); + // tokens.add( tokenizer.nextToken("e") ); + } + int tokenLength = tokens.size(); + return tokens; + } + + public List getTokensWithCollection(String str) { + StringTokenizer tokenizer = new StringTokenizer(str, ","); + + return Collections.list(tokenizer).stream() + .map(token -> (String) token) + .collect(Collectors.toList()); + } + + public List getTokensFromFile(String path, String delim) { + List tokens = new ArrayList<>(); + String currLine = ""; + StringTokenizer tokenizer; + try (BufferedReader br = new BufferedReader(new InputStreamReader(Application.class.getResourceAsStream("/" + path)))) { + while ((currLine = br.readLine()) != null) { + tokenizer = new StringTokenizer(currLine, delim); + while (tokenizer.hasMoreElements()) { + tokens.add(tokenizer.nextToken()); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return tokens; + } } From a3926e42042c9ca4caf2661f4f47760bdd4ff3da Mon Sep 17 00:00:00 2001 From: lor6 Date: Fri, 7 Apr 2017 23:30:29 +0300 Subject: [PATCH 268/291] separate test datasource (#1575) * separate test datasource * remove hsqldb * fix var name * move config class --- spring-boot/pom.xml | 2 + .../java/org/baeldung/config/H2JpaConfig.java | 67 +++++++++++++++++++ .../baeldung/SpringBootH2IntegrationTest.java | 28 ++++++++ .../SpringBootJPAIntegrationTest.java | 6 +- .../SpringBootProfileIntegrationTest.java | 30 +++++++++ .../config/H2TestProfileJPAConfig.java | 66 ++++++++++++++++++ .../src/test/resources/application.properties | 16 ++++- .../persistence-generic-entity.properties | 8 +++ 8 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 spring-boot/src/main/java/org/baeldung/config/H2JpaConfig.java create mode 100644 spring-boot/src/test/java/org/baeldung/SpringBootH2IntegrationTest.java create mode 100644 spring-boot/src/test/java/org/baeldung/SpringBootProfileIntegrationTest.java create mode 100644 spring-boot/src/test/java/org/baeldung/config/H2TestProfileJPAConfig.java create mode 100644 spring-boot/src/test/resources/persistence-generic-entity.properties diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index f087617709..5f77be43e3 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -67,6 +67,7 @@ com.h2database h2 + ${h2.version} @@ -219,6 +220,7 @@ 3.3.7-1 3.1.7 8.5.11 + 1.4.194 diff --git a/spring-boot/src/main/java/org/baeldung/config/H2JpaConfig.java b/spring-boot/src/main/java/org/baeldung/config/H2JpaConfig.java new file mode 100644 index 0000000000..ace7bb5a6d --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/config/H2JpaConfig.java @@ -0,0 +1,67 @@ +package org.baeldung.config; + +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableJpaRepositories(basePackages = { "org.baeldung.repository", "org.baeldung.boot.repository" }) +@PropertySource("classpath:persistence-generic-entity.properties") +@EnableTransactionManagement +public class H2JpaConfig { + + @Autowired + private Environment env; + + @Bean + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName")); + dataSource.setUrl(env.getProperty("jdbc.url")); + dataSource.setUsername(env.getProperty("jdbc.user")); + dataSource.setPassword(env.getProperty("jdbc.pass")); + + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "org.baeldung.domain", "org.baeldung.boot.model" }); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaProperties(additionalProperties()); + return em; + } + + @Bean + JpaTransactionManager transactionManager(final EntityManagerFactory entityManagerFactory) { + final JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory); + return transactionManager; + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + + return hibernateProperties; + } + +} diff --git a/spring-boot/src/test/java/org/baeldung/SpringBootH2IntegrationTest.java b/spring-boot/src/test/java/org/baeldung/SpringBootH2IntegrationTest.java new file mode 100644 index 0000000000..185a36e571 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/SpringBootH2IntegrationTest.java @@ -0,0 +1,28 @@ +package org.baeldung; + +import org.baeldung.config.H2JpaConfig; +import org.baeldung.domain.GenericEntity; +import org.baeldung.repository.GenericEntityRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = { Application.class, H2JpaConfig.class }) +public class SpringBootH2IntegrationTest { + @Autowired + private GenericEntityRepository genericEntityRepository; + + @Test + public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() { + GenericEntity genericEntity = genericEntityRepository.save(new GenericEntity("test")); + GenericEntity foundEntity = genericEntityRepository.findOne(genericEntity.getId()); + assertNotNull(foundEntity); + assertEquals(genericEntity.getValue(), foundEntity.getValue()); + } +} \ No newline at end of file diff --git a/spring-boot/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java index d4b19e6a1d..202d24ffc7 100644 --- a/spring-boot/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java +++ b/spring-boot/src/test/java/org/baeldung/SpringBootJPAIntegrationTest.java @@ -20,8 +20,8 @@ public class SpringBootJPAIntegrationTest { @Test public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() { GenericEntity genericEntity = genericEntityRepository.save(new GenericEntity("test")); - GenericEntity foundedEntity = genericEntityRepository.findOne(genericEntity.getId()); - assertNotNull(foundedEntity); - assertEquals(genericEntity.getValue(), foundedEntity.getValue()); + GenericEntity foundEntity = genericEntityRepository.findOne(genericEntity.getId()); + assertNotNull(foundEntity); + assertEquals(genericEntity.getValue(), foundEntity.getValue()); } } diff --git a/spring-boot/src/test/java/org/baeldung/SpringBootProfileIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/SpringBootProfileIntegrationTest.java new file mode 100644 index 0000000000..806b38a8ce --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/SpringBootProfileIntegrationTest.java @@ -0,0 +1,30 @@ +package org.baeldung; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.baeldung.config.H2TestProfileJPAConfig; +import org.baeldung.domain.GenericEntity; +import org.baeldung.repository.GenericEntityRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = { Application.class, H2TestProfileJPAConfig.class }) +@ActiveProfiles("test") +public class SpringBootProfileIntegrationTest { + @Autowired + private GenericEntityRepository genericEntityRepository; + + @Test + public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() { + GenericEntity genericEntity = genericEntityRepository.save(new GenericEntity("test")); + GenericEntity foundEntity = genericEntityRepository.findOne(genericEntity.getId()); + assertNotNull(foundEntity); + assertEquals(genericEntity.getValue(), foundEntity.getValue()); + } +} diff --git a/spring-boot/src/test/java/org/baeldung/config/H2TestProfileJPAConfig.java b/spring-boot/src/test/java/org/baeldung/config/H2TestProfileJPAConfig.java new file mode 100644 index 0000000000..1d696f4a5d --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/config/H2TestProfileJPAConfig.java @@ -0,0 +1,66 @@ +package org.baeldung.config; + +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableJpaRepositories(basePackages = { "org.baeldung.repository", "org.baeldung.boot.repository" }) +@EnableTransactionManagement +public class H2TestProfileJPAConfig { + + @Autowired + private Environment env; + + @Bean + @Profile("test") + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"); + dataSource.setUsername("sa"); + dataSource.setPassword("sa"); + + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "org.baeldung.domain", "org.baeldung.boot.model" }); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaProperties(additionalProperties()); + return em; + } + + @Bean + JpaTransactionManager transactionManager(final EntityManagerFactory entityManagerFactory) { + final JpaTransactionManager transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(entityManagerFactory); + return transactionManager; + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + + return hibernateProperties; + } +} diff --git a/spring-boot/src/test/resources/application.properties b/spring-boot/src/test/resources/application.properties index 0e6cb86bc5..85e4e6e66f 100644 --- a/spring-boot/src/test/resources/application.properties +++ b/spring-boot/src/test/resources/application.properties @@ -2,4 +2,18 @@ spring.mail.host=localhost spring.mail.port=8025 spring.mail.properties.mail.smtp.auth=false -security.basic.enabled=false \ No newline at end of file +security.basic.enabled=false + +# spring.datasource.x +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +spring.datasource.username=sa +spring.datasource.password=sa + +# hibernate.X +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop +hibernate.cache.use_second_level_cache=true +hibernate.cache.use_query_cache=true +hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory \ No newline at end of file diff --git a/spring-boot/src/test/resources/persistence-generic-entity.properties b/spring-boot/src/test/resources/persistence-generic-entity.properties new file mode 100644 index 0000000000..c60e7488b6 --- /dev/null +++ b/spring-boot/src/test/resources/persistence-generic-entity.properties @@ -0,0 +1,8 @@ +jdbc.driverClassName=org.h2.Driver +jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 +jdbc.username=sa +jdbc.password=sa + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file From 6bf3659fb58dfbe19f63d854d7ece76b54fad532 Mon Sep 17 00:00:00 2001 From: "Eunice A. Obugyei" Date: Fri, 7 Apr 2017 20:37:47 +0000 Subject: [PATCH 269/291] Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] (#1566) * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Removed unnecessary comment * Added mockito-core dependency * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] Added Exception test cases * Applied baeldung formatter in Eclipse * Merged from https://github.com/eugenp/tutorials Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Revert "Merged from https://github.com/eugenp/tutorials" This reverts commit 74447a163b9e3f244a2578315fbdb525d20cd16b. * Introduction to JAX-WS[http://jira.baeldung.com/browse/BAEL-611] * Removed mockito version from properties --- .../com/baeldung/jaxws/exception/EmployeeAlreadyExists.java | 6 +----- .../java/com/baeldung/jaxws/exception/EmployeeNotFound.java | 3 +-- jee7/src/main/java/com/baeldung/jaxws/model/Employee.java | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java index 4842fbf84c..8a96f8aec0 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java +++ b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeAlreadyExists.java @@ -1,13 +1,9 @@ package com.baeldung.jaxws.exception; -import java.io.Serializable; - import javax.xml.ws.WebFault; @WebFault -public class EmployeeAlreadyExists extends Exception implements Serializable { - - private static final long serialVersionUID = 1L; +public class EmployeeAlreadyExists extends Exception { public EmployeeAlreadyExists() { super("This employee already exists"); diff --git a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java index 667e3e0c72..3de2ca8db6 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java +++ b/jee7/src/main/java/com/baeldung/jaxws/exception/EmployeeNotFound.java @@ -1,10 +1,9 @@ package com.baeldung.jaxws.exception; import javax.xml.ws.WebFault; -import java.io.Serializable; @WebFault -public class EmployeeNotFound extends Exception implements Serializable { +public class EmployeeNotFound extends Exception { public EmployeeNotFound() { super("The specified employee does not exist"); diff --git a/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java index 5b1673c1e4..dbbdc234cf 100644 --- a/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java +++ b/jee7/src/main/java/com/baeldung/jaxws/model/Employee.java @@ -1,9 +1,6 @@ package com.baeldung.jaxws.model; -import java.io.Serializable; - -public class Employee implements Serializable { - private static final long serialVersionUID = 1L; +public class Employee { private int id; private String firstName; From f5437fefaaf5dd5118a8fd6eb1dc502ead5f17f9 Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Fri, 7 Apr 2017 22:42:32 +0200 Subject: [PATCH 270/291] Fix integration test (#1607) * upgrade to spring boot 1.5.2 * add full update to REST API * modify ratings controller * upgrade herold * fix integration test * fix integration test --- apache-fop/pom.xml | 4 +-- .../ApacheFOPConvertHTMLIntegrationTest.java | 25 ++++++------- .../java/ApacheFOPHeroldLiveTest.java | 34 +++++++++--------- apache-fop/src/test/resources/jars/herold.jar | Bin 847837 -> 0 bytes .../java/org/baeldung/sample/AppConfig.java | 2 +- spring-data-neo4j/pom.xml | 15 ++++---- .../MovieDatabaseNeo4jTestConfiguration.java | 11 +++--- 7 files changed, 47 insertions(+), 44 deletions(-) delete mode 100644 apache-fop/src/test/resources/jars/herold.jar diff --git a/apache-fop/pom.xml b/apache-fop/pom.xml index 6337fe002c..6075c23d21 100644 --- a/apache-fop/pom.xml +++ b/apache-fop/pom.xml @@ -101,9 +101,7 @@ org.dbdoclet herold - 6.1.0 - system - ${basedir}/src/test/resources/jars/herold.jar + 8.0.4 diff --git a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPConvertHTMLIntegrationTest.java b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPConvertHTMLIntegrationTest.java index 99487c8fdf..5e2da6fd1e 100644 --- a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPConvertHTMLIntegrationTest.java +++ b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPConvertHTMLIntegrationTest.java @@ -19,21 +19,21 @@ import javax.xml.transform.stream.StreamSource; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.xmlgraphics.util.MimeConstants; -import org.dbdoclet.trafo.html.docbook.DocBookTransformer; +import org.dbdoclet.trafo.html.docbook.HtmlDocBookTrafo; import org.dbdoclet.trafo.script.Script; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.tidy.Tidy; public class ApacheFOPConvertHTMLIntegrationTest { - private String inputFile = "src/test/resources/input.html"; - private String style = "src/test/resources/xhtml2fo.xsl"; - private String style1 = "src/test/resources/docbook-xsl/fo/docbook.xsl"; - private String output_jtidy = "src/test/resources/output_jtidy.pdf"; - private String output_html2fo = "src/test/resources/output_html2fo.pdf"; - private String output_herold = "src/test/resources/output_herold.pdf"; - private String foFile = "src/test/resources/input.fo"; - private String xmlFile = "src/test/resources/input.xml"; + private final String inputFile = "src/test/resources/input.html"; + private final String style = "src/test/resources/xhtml2fo.xsl"; + private final String style1 = "src/test/resources/docbook-xsl/fo/docbook.xsl"; + private final String output_jtidy = "src/test/resources/output_jtidy.pdf"; + private final String output_html2fo = "src/test/resources/output_html2fo.pdf"; + private final String output_herold = "src/test/resources/output_herold.pdf"; + private final String foFile = "src/test/resources/input.fo"; + private final String xmlFile = "src/test/resources/input.xml"; @Test public void whenTransformHTMLToPDFUsingJTidy_thenCorrect() throws Exception { @@ -114,8 +114,9 @@ public class ApacheFOPConvertHTMLIntegrationTest { private void fromHTMLTOXMLUsingHerold() throws Exception { final Script script = new Script(); - final DocBookTransformer transformer = new DocBookTransformer(); - transformer.setScript(script); - transformer.convert(new FileInputStream(inputFile), new FileOutputStream(xmlFile)); + final HtmlDocBookTrafo transformer = new HtmlDocBookTrafo(); + transformer.setInputStream(new FileInputStream(inputFile)); + transformer.setOutputStream(new FileOutputStream(xmlFile)); + transformer.transform(script); } } diff --git a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldLiveTest.java b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldLiveTest.java index 9e71cd9c16..8496222394 100644 --- a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldLiveTest.java +++ b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldLiveTest.java @@ -10,6 +10,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.HttpURLConnection; import java.net.URL; import javax.xml.transform.Result; @@ -25,19 +26,15 @@ import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.xmlgraphics.util.MimeConstants; import org.dbdoclet.trafo.TrafoScriptManager; -import org.dbdoclet.trafo.html.docbook.DocBookTransformer; +import org.dbdoclet.trafo.html.docbook.HtmlDocBookTrafo; import org.dbdoclet.trafo.script.Script; import org.junit.Test; import org.w3c.dom.Document; public class ApacheFOPHeroldLiveTest { - private String[] inputUrls = {// @formatter:off - "http://www.baeldung.com/2011/10/20/bootstraping-a-web-application-with-spring-3-1-and-java-based-configuration-part-1/", - "http://www.baeldung.com/2011/10/25/building-a-restful-web-service-with-spring-3-1-and-java-based-configuration-part-2/", - "http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/", - "http://www.baeldung.com/spring-security-basic-authentication", - "http://www.baeldung.com/spring-security-digest-authentication", - "http://www.baeldung.com/2011/11/20/basic-and-digest-authentication-for-a-restful-service-with-spring-security-3-1/", + private final String[] inputUrls = {// @formatter:off + // "http://www.baeldung.com/spring-security-basic-authentication", + "http://www.baeldung.com/spring-security-digest-authentication" //"http://www.baeldung.com/spring-httpmessageconverter-rest", //"http://www.baeldung.com/2011/11/06/restful-web-service-discoverability-part-4/", //"http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/", @@ -49,10 +46,10 @@ public class ApacheFOPHeroldLiveTest { //"http://www.baeldung.com/2013/01/18/testing-rest-with-multiple-mime-types/" }; // @formatter:on - private String style_file = "src/test/resources/docbook-xsl/fo/docbook.xsl"; - private String output_file = "src/test/resources/final_output.pdf"; - private String xmlInput = "src/test/resources/input.xml"; - private String xmlOutput = "src/test/resources/output.xml"; + private final String style_file = "src/test/resources/docbook-xsl/fo/docbook.xsl"; + private final String output_file = "src/test/resources/final_output.pdf"; + private final String xmlInput = "src/test/resources/input.xml"; + private final String xmlOutput = "src/test/resources/output.xml"; // tests @@ -75,10 +72,11 @@ public class ApacheFOPHeroldLiveTest { final TrafoScriptManager mgr = new TrafoScriptManager(); final File profileFile = new File("src/test/resources/default.her"); script = mgr.parseScript(profileFile); - final DocBookTransformer transformer = new DocBookTransformer(); - transformer.setScript(script); + final HtmlDocBookTrafo transformer = new HtmlDocBookTrafo(); + transformer.setInputStream(getInputStream(input)); + transformer.setOutputStream(new FileOutputStream(xmlInput, append)); - transformer.convert(getInputStream(input), new FileOutputStream(xmlInput, append)); + transformer.transform(script); } private Document fromXMLFileToFO() throws Exception { @@ -112,7 +110,9 @@ public class ApacheFOPHeroldLiveTest { private InputStream getInputStream(final String input) throws IOException { final URL url = new URL(input); - return url.openStream(); + final HttpURLConnection httpcon = (HttpURLConnection) url.openConnection(); + httpcon.addRequestProperty("User-Agent", "Mozilla/4.0"); + return httpcon.getInputStream(); } private void fixXML(final String input, final String output) throws IOException { @@ -127,7 +127,7 @@ public class ApacheFOPHeroldLiveTest { if (line.contains("info>")) { writer.write(line.replace("info>", "section>")); - } else if (!((line.startsWith(" 4)) { + } else if (!((line.startsWith(" 4))) { writer.write(line.replaceAll("xml:id=\"", "xml:id=\"" + count)); } writer.write("\n"); diff --git a/apache-fop/src/test/resources/jars/herold.jar b/apache-fop/src/test/resources/jars/herold.jar deleted file mode 100644 index ef5d052f3667bab43dc8e217b0a89b26a2952904..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 847837 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πzIffu08N1Ab@- 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%0D%$|pO8_)>{ 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 z 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Π}W~&k_weILy0; zx}Nw7Fj}xX0ePX9m_00a^9DVe>vW}uD!b#~8f#+nTT;@Fic>Rs;N*@kmJ1mR82Ssa zhG=69=Xwfqom<|CEwiAf3B#-r>pF|4@n~@obh|LM9KLqJm-c?Kzvp780 zlrYxllC4Tu*8-PlosKkaS?NT9qNsfu{;=hrGG8Qtx*EQ|??du5qdQ~ipf;O}-C7`{ zwU4E~fPWtlX&Jh@S&Oyc9t4+-cb6Bba|K&e2>i5N!m1Sj(^~{yO!c2jlz}^OZ{Q+g z6VHKP(PcVoL1Y8cE}RH*Yn-ksbLC!ovqNCjo~47{ZNj{nH&S%gs;ifakZLQNq-s+5 z&c|5U(M>9{)v@o{Pwn7mpu$Drb5v zJJh+!&491*&u=0G03T|jJdbL?-eVuV>Wl_S@r@JW;4 z>VAkv?45x?>2#X;<=nGcFboR6a9w36z|aI!8g-BiOvOY zMNGlcIjMNOU4u1+De*wWuaX9%9=YcSDNeai{ska9-NK9uGv>ap({0O)9!d9qAz>FV diff --git a/spring-all/src/main/java/org/baeldung/sample/AppConfig.java b/spring-all/src/main/java/org/baeldung/sample/AppConfig.java index ffc792d9df..8a177d2611 100644 --- a/spring-all/src/main/java/org/baeldung/sample/AppConfig.java +++ b/spring-all/src/main/java/org/baeldung/sample/AppConfig.java @@ -4,7 +4,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration -@ComponentScan("com.baeldung.autowire.sample") +@ComponentScan("org.baeldung.sample") public class AppConfig { } diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 96606d597b..7df48498e5 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -10,31 +10,31 @@ org.neo4j neo4j - 3.1.0 + ${neo4j.version} org.neo4j neo4j-ogm-core - 2.1.1 + ${neo4j-ogm.version} org.neo4j neo4j-ogm-embedded-driver - 2.1.1 + ${neo4j-ogm.version} org.neo4j.driver neo4j-java-driver - 1.1.1 + ${neo4j-java-driver.version} org.springframework.data spring-data-neo4j - 4.2.0.RELEASE + ${spring-data-neo4j.version} @@ -75,7 +75,7 @@ org.neo4j neo4j-ogm-test - ${neo4j-ogm-test.version} + ${neo4j-ogm.version} test @@ -160,12 +160,13 @@ UTF-8 UTF-8 + 1.1.1 3.1.0 4.1.6.RELEASE 1.1 1.4.3.RELEASE 4.3.5.RELEASE - 2.1.1 + 2.1.1 4.12 diff --git a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java index 7bb1b78a09..fda478e5be 100644 --- a/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java +++ b/spring-data-neo4j/src/main/java/com/baeldung/spring/data/neo4j/config/MovieDatabaseNeo4jTestConfiguration.java @@ -5,20 +5,22 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.data.neo4j.config.Neo4jConfiguration; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; +@Configuration @EnableTransactionManagement @ComponentScan(basePackages = { "com.baeldung.spring.data.neo4j.services" }) -@Configuration @EnableNeo4jRepositories(basePackages = "com.baeldung.spring.data.neo4j.repostory") @Profile({ "embedded", "test" }) -public class MovieDatabaseNeo4jTestConfiguration { +public class MovieDatabaseNeo4jTestConfiguration extends Neo4jConfiguration { @Bean public org.neo4j.ogm.config.Configuration getConfiguration() { - org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration(); - config.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"); + final org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration(); + config.driverConfiguration() + .setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"); return config; } @@ -26,4 +28,5 @@ public class MovieDatabaseNeo4jTestConfiguration { public SessionFactory getSessionFactory() { return new SessionFactory(getConfiguration(), "com.baeldung.spring.data.neo4j.domain"); } + } From 13a42ea2814e2505e74121600a08bf2a256a0a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Ju=C3=A1rez?= Date: Sat, 8 Apr 2017 04:48:47 -0500 Subject: [PATCH 271/291] Intro to JasperReports with Spring (#1608) --- spring-all/pom.xml | 7 ++ .../java/org/baeldung/jasperreports/Main.java | 39 ++++++ .../jasperreports/SimpleReportExporter.java | 115 ++++++++++++++++++ .../jasperreports/SimpleReportFiller.java | 90 ++++++++++++++ .../config/JasperRerportsSimpleConfig.java | 32 +++++ .../src/main/resources/employee-schema.sql | 27 ++++ .../main/resources/employeeEmailReport.jrxml | 17 +++ .../src/main/resources/employeeReport.jrxml | 51 ++++++++ 8 files changed, 378 insertions(+) create mode 100644 spring-all/src/main/java/org/baeldung/jasperreports/Main.java create mode 100644 spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportExporter.java create mode 100644 spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportFiller.java create mode 100644 spring-all/src/main/java/org/baeldung/jasperreports/config/JasperRerportsSimpleConfig.java create mode 100644 spring-all/src/main/resources/employee-schema.sql create mode 100644 spring-all/src/main/resources/employeeEmailReport.jrxml create mode 100644 spring-all/src/main/resources/employeeReport.jrxml diff --git a/spring-all/pom.xml b/spring-all/pom.xml index a3a51425e2..eb7a573c89 100644 --- a/spring-all/pom.xml +++ b/spring-all/pom.xml @@ -106,6 +106,12 @@ guava ${guava.version} + + + net.sf.jasperreports + jasperreports + ${jasperreports.version} + @@ -296,6 +302,7 @@ 3.1.3 3.4 3.6.1 + 6.4.0 diff --git a/spring-all/src/main/java/org/baeldung/jasperreports/Main.java b/spring-all/src/main/java/org/baeldung/jasperreports/Main.java new file mode 100644 index 0000000000..79aee100a6 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/jasperreports/Main.java @@ -0,0 +1,39 @@ +package org.baeldung.jasperreports; + +import java.util.HashMap; +import java.util.Map; +import org.baeldung.jasperreports.config.JasperRerportsSimpleConfig; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class Main { + public static void main(String[] args) { + + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(JasperRerportsSimpleConfig.class); + ctx.refresh(); + + SimpleReportFiller simpleReportFiller = ctx.getBean(SimpleReportFiller.class); + simpleReportFiller.setReportFileName("employeeEmailReport.jrxml"); + simpleReportFiller.compileReport(); + + simpleReportFiller.setReportFileName("employeeReport.jrxml"); + simpleReportFiller.compileReport(); + + Map parameters = new HashMap<>(); + parameters.put("title", "Employee Report Example"); + parameters.put("minSalary", 15000.0); + parameters.put("condition", " LAST_NAME ='Smith' ORDER BY FIRST_NAME"); + + simpleReportFiller.setParameters(parameters); + simpleReportFiller.fillReport(); + + SimpleReportExporter simpleExporter = ctx.getBean(SimpleReportExporter.class); + simpleExporter.setJasperPrint(simpleReportFiller.getJasperPrint()); + + simpleExporter.exportToPdf("employeeReport.pdf", "baeldung"); + simpleExporter.exportToXlsx("employeeReport.xlsx", "Employee Data"); + simpleExporter.exportToCsv("employeeReport.csv"); + simpleExporter.exportToHtml("employeeReport.html"); + + } +} diff --git a/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportExporter.java b/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportExporter.java new file mode 100644 index 0000000000..1252dcda4d --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportExporter.java @@ -0,0 +1,115 @@ +package org.baeldung.jasperreports; + +import java.util.logging.Level; +import java.util.logging.Logger; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.export.HtmlExporter; +import net.sf.jasperreports.engine.export.JRCsvExporter; +import net.sf.jasperreports.engine.export.JRPdfExporter; +import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter; +import net.sf.jasperreports.export.SimpleExporterInput; +import net.sf.jasperreports.export.SimpleHtmlExporterOutput; +import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput; +import net.sf.jasperreports.export.SimplePdfExporterConfiguration; +import net.sf.jasperreports.export.SimplePdfReportConfiguration; +import net.sf.jasperreports.export.SimpleWriterExporterOutput; +import net.sf.jasperreports.export.SimpleXlsxReportConfiguration; +import org.springframework.stereotype.Component; + +@Component +public class SimpleReportExporter { + + private JasperPrint jasperPrint; + + public SimpleReportExporter() { + } + + public SimpleReportExporter (JasperPrint jasperPrint){ + this.jasperPrint = jasperPrint; + } + + public JasperPrint getJasperPrint() { + return jasperPrint; + } + + public void setJasperPrint(JasperPrint jasperPrint) { + this.jasperPrint = jasperPrint; + } + + + + public void exportToPdf(String fileName, String author) { + + // print report to file + JRPdfExporter exporter = new JRPdfExporter(); + + exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(fileName)); + + SimplePdfReportConfiguration reportConfig = new SimplePdfReportConfiguration(); + reportConfig.setSizePageToContent(true); + reportConfig.setForceLineBreakPolicy(false); + + SimplePdfExporterConfiguration exportConfig = new SimplePdfExporterConfiguration(); + exportConfig.setMetadataAuthor(author); + exportConfig.setEncrypted(true); + exportConfig.setAllowedPermissionsHint("PRINTING"); + + exporter.setConfiguration(reportConfig); + exporter.setConfiguration(exportConfig); + try { + exporter.exportReport(); + } catch (JRException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public void exportToXlsx(String fileName,String sheetName) { + JRXlsxExporter exporter = new JRXlsxExporter(); + + exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(fileName)); + + SimpleXlsxReportConfiguration reportConfig = new SimpleXlsxReportConfiguration(); + reportConfig.setSheetNames(new String[]{sheetName}); + + exporter.setConfiguration(reportConfig); + + try { + exporter.exportReport(); + } catch (JRException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public void exportToCsv(String fileName) { + JRCsvExporter exporter = new JRCsvExporter(); + + exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + exporter.setExporterOutput(new SimpleWriterExporterOutput(fileName)); + + try { + exporter.exportReport(); + } catch (JRException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public void exportToHtml(String fileName) { + HtmlExporter exporter = new HtmlExporter(); + + exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + exporter.setExporterOutput(new SimpleHtmlExporterOutput(fileName)); + + try { + exporter.exportReport(); + } catch (JRException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } +} diff --git a/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportFiller.java b/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportFiller.java new file mode 100644 index 0000000000..ae675dd280 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/jasperreports/SimpleReportFiller.java @@ -0,0 +1,90 @@ +package org.baeldung.jasperreports; + +import java.io.InputStream; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.sql.DataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperCompileManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JasperReport; +import net.sf.jasperreports.engine.util.JRSaver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SimpleReportFiller { + + private String reportFileName; + + private JasperReport jasperReport; + + private JasperPrint jasperPrint; + + @Autowired + private DataSource dataSource; + + private Map parameters; + + public SimpleReportFiller() { + parameters = new HashMap<>(); + } + + public void prepareReport() { + compileReport(); + fillReport(); + } + + public void compileReport() { + try { + InputStream reportStream = getClass().getResourceAsStream("/".concat(reportFileName)); + jasperReport = JasperCompileManager.compileReport(reportStream); + JRSaver.saveObject(jasperReport, reportFileName.replace(".jrxml", ".jasper")); + } catch (JRException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public void fillReport() { + try { + jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource.getConnection()); + } catch (JRException | SQLException ex) { + Logger.getLogger(SimpleReportFiller.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public String getReportFileName() { + return reportFileName; + } + + public void setReportFileName(String reportFileName) { + this.reportFileName = reportFileName; + } + + public JasperPrint getJasperPrint() { + return jasperPrint; + } + +} diff --git a/spring-all/src/main/java/org/baeldung/jasperreports/config/JasperRerportsSimpleConfig.java b/spring-all/src/main/java/org/baeldung/jasperreports/config/JasperRerportsSimpleConfig.java new file mode 100644 index 0000000000..90fc96cdbb --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/jasperreports/config/JasperRerportsSimpleConfig.java @@ -0,0 +1,32 @@ +package org.baeldung.jasperreports.config; + +import javax.sql.DataSource; +import org.baeldung.jasperreports.SimpleReportExporter; +import org.baeldung.jasperreports.SimpleReportFiller; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; + +@Configuration +public class JasperRerportsSimpleConfig { + + @Bean + public DataSource dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.HSQL) + .addScript("classpath:employee-schema.sql") + .build(); + } + + @Bean + public SimpleReportFiller reportFiller() { + return new SimpleReportFiller(); + } + + @Bean + public SimpleReportExporter reportExporter() { + return new SimpleReportExporter(); + } + +} diff --git a/spring-all/src/main/resources/employee-schema.sql b/spring-all/src/main/resources/employee-schema.sql new file mode 100644 index 0000000000..011ff162e1 --- /dev/null +++ b/spring-all/src/main/resources/employee-schema.sql @@ -0,0 +1,27 @@ +CREATE TABLE EMPLOYEE( + ID INT NOT NULL PRIMARY KEY, + FIRST_NAME VARCHAR(255), + LAST_NAME VARCHAR(255), + SALARY DOUBLE, +); + +CREATE TABLE EMAIL( + ID INT NOT NULL PRIMARY KEY, + ID_EMPLOYEE VARCHAR(255), + ADDRESS VARCHAR(255) +); + +INSERT INTO EMPLOYEE VALUES (1, 'John', 'Doe', 10000.10); +INSERT INTO EMPLOYEE VALUES (2, 'Kevin', 'Smith', 20000.20); +INSERT INTO EMPLOYEE VALUES (3, 'Kim', 'Smith', 30000.30); +INSERT INTO EMPLOYEE VALUES (4, 'Stephen', 'Torvalds', 40000.40); +INSERT INTO EMPLOYEE VALUES (5, 'Christian', 'Reynolds', 50000.50); + +INSERT INTO EMAIL VALUES (1, 1, 'john@baeldung.com'); +INSERT INTO EMAIL VALUES (2, 1, 'john@gmail.com'); +INSERT INTO EMAIL VALUES (3, 2, 'kevin@baeldung.com'); +INSERT INTO EMAIL VALUES (4, 3, 'kim@baeldung.com'); +INSERT INTO EMAIL VALUES (5, 3, 'kim@gmail.com'); +INSERT INTO EMAIL VALUES (6, 3, 'kim@outlook.com'); +INSERT INTO EMAIL VALUES (7, 4, 'stephen@baeldung.com'); +INSERT INTO EMAIL VALUES (8, 5, 'christian@gmail.com'); diff --git a/spring-all/src/main/resources/employeeEmailReport.jrxml b/spring-all/src/main/resources/employeeEmailReport.jrxml new file mode 100644 index 0000000000..ad4aaaac90 --- /dev/null +++ b/spring-all/src/main/resources/employeeEmailReport.jrxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/spring-all/src/main/resources/employeeReport.jrxml b/spring-all/src/main/resources/employeeReport.jrxml new file mode 100644 index 0000000000..3d2be226fb --- /dev/null +++ b/spring-all/src/main/resources/employeeReport.jrxml @@ -0,0 +1,51 @@ + + + + + + + + + = $P{minSalary} AND $P!{condition}]]> + + + + + + + <band height="20" splitType="Stretch"> + <textField> + <reportElement x="238" y="0" width="100" height="20"/> + <textElement/> + <textFieldExpression class="java.lang.String"><![CDATA[$P{title}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 60c2edaaeb78110ab664e3929c8738b2481aecaf Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Sat, 8 Apr 2017 13:49:01 +0200 Subject: [PATCH 272/291] StringTokenizerTest refactor (#1611) * TokenizerRefactor * TokenizerRefactor * TokenizerRefactor --- .../{Application.java => MyTokenizer.java} | 14 +++--- .../stringtokenizer/ApplicationTest.java | 47 ------------------- .../stringtokenizer/TokenizerTest.java | 29 ++++++++++++ 3 files changed, 36 insertions(+), 54 deletions(-) rename core-java/src/main/java/com/baeldung/stringtokenizer/{Application.java => MyTokenizer.java} (83%) delete mode 100644 core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java create mode 100644 core-java/src/test/java/com/baeldung/stringtokenizer/TokenizerTest.java diff --git a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java b/core-java/src/main/java/com/baeldung/stringtokenizer/MyTokenizer.java similarity index 83% rename from core-java/src/main/java/com/baeldung/stringtokenizer/Application.java rename to core-java/src/main/java/com/baeldung/stringtokenizer/MyTokenizer.java index 4560e40697..130218acc2 100644 --- a/core-java/src/main/java/com/baeldung/stringtokenizer/Application.java +++ b/core-java/src/main/java/com/baeldung/stringtokenizer/MyTokenizer.java @@ -9,10 +9,10 @@ import java.util.List; import java.util.StringTokenizer; import java.util.stream.Collectors; -public class Application { +public class MyTokenizer { public List getTokens(String str) { - List tokens = new ArrayList(); + List tokens = new ArrayList<>(); // StringTokenizer tokenizer = new StringTokenizer( str ); StringTokenizer tokenizer = new StringTokenizer(str, ","); // StringTokenizer tokenizer = new StringTokenizer( str , "," , true ); @@ -25,18 +25,18 @@ public class Application { } public List getTokensWithCollection(String str) { - StringTokenizer tokenizer = new StringTokenizer(str, ","); - - return Collections.list(tokenizer).stream() + return Collections + .list(new StringTokenizer(str, ",")) + .stream() .map(token -> (String) token) .collect(Collectors.toList()); } public List getTokensFromFile(String path, String delim) { List tokens = new ArrayList<>(); - String currLine = ""; + String currLine; StringTokenizer tokenizer; - try (BufferedReader br = new BufferedReader(new InputStreamReader(Application.class.getResourceAsStream("/" + path)))) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(MyTokenizer.class.getResourceAsStream("/" + path)))) { while ((currLine = br.readLine()) != null) { tokenizer = new StringTokenizer(currLine, delim); while (tokenizer.hasMoreElements()) { diff --git a/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java b/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java deleted file mode 100644 index 5d475d2fbb..0000000000 --- a/core-java/src/test/java/com/baeldung/stringtokenizer/ApplicationTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.stringtokenizer; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class ApplicationTest { - - Application application = new Application(); - List expectedTokensForString = new ArrayList(); - List expectedTokensForFile = new ArrayList(); - - @Before - public void init() { - expectedTokensForString.add("Welcome"); - expectedTokensForString.add("to"); - expectedTokensForString.add("baeldung.com"); - - expectedTokensForFile.add("1"); - expectedTokensForFile.add("IND"); - expectedTokensForFile.add("India"); - expectedTokensForFile.add("2"); - expectedTokensForFile.add("MY"); - expectedTokensForFile.add("Malaysia"); - expectedTokensForFile.add("3"); - expectedTokensForFile.add("AU"); - expectedTokensForFile.add("Australia"); - } - - @Test - public void givenString_thenGetListOfString() { - String str = "Welcome,to,baeldung.com"; - List actualTokens = application.getTokens(str); - assertEquals(expectedTokensForString, actualTokens); - } - - @Test - public void givenFile_thenGetListOfString() { - List actualTokens = application.getTokensFromFile("data.csv", "|"); - assertEquals(expectedTokensForFile, actualTokens); - } - -} diff --git a/core-java/src/test/java/com/baeldung/stringtokenizer/TokenizerTest.java b/core-java/src/test/java/com/baeldung/stringtokenizer/TokenizerTest.java new file mode 100644 index 0000000000..eed42a2f96 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/stringtokenizer/TokenizerTest.java @@ -0,0 +1,29 @@ +package com.baeldung.stringtokenizer; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class TokenizerTest { + + private final MyTokenizer myTokenizer = new MyTokenizer(); + private final List expectedTokensForString = Arrays.asList("Welcome", "to", "baeldung.com"); + private final List expectedTokensForFile = Arrays.asList("1", "IND", "India", "2", "MY", "Malaysia", "3", "AU", "Australia"); + + @Test + public void givenString_thenGetListOfString() { + String str = "Welcome,to,baeldung.com"; + List actualTokens = myTokenizer.getTokens(str); + assertEquals(expectedTokensForString, actualTokens); + } + + @Test + public void givenFile_thenGetListOfString() { + List actualTokens = myTokenizer.getTokensFromFile("data.csv", "|"); + assertEquals(expectedTokensForFile, actualTokens); + } + +} From c0509dd1ee1f2b7b09b1ac5756f8324e520ac51e Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Sat, 8 Apr 2017 15:47:42 +0200 Subject: [PATCH 273/291] minor fix (#1612) * upgrade to spring boot 1.5.2 * add full update to REST API * modify ratings controller * upgrade herold * fix integration test * fix integration test * minor fix --- spring-data-solr/pom.xml | 34 --------------------------- spring-security-cache-control/pom.xml | 3 +++ 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/spring-data-solr/pom.xml b/spring-data-solr/pom.xml index e43b3ff774..fd6c442abf 100644 --- a/spring-data-solr/pom.xml +++ b/spring-data-solr/pom.xml @@ -72,38 +72,4 @@ - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - \ No newline at end of file diff --git a/spring-security-cache-control/pom.xml b/spring-security-cache-control/pom.xml index f25e85012e..b24b9db484 100644 --- a/spring-security-cache-control/pom.xml +++ b/spring-security-cache-control/pom.xml @@ -81,6 +81,9 @@ + UTF-8 + 1.8 + 3.1.0 2.9.0 From 1e8bcdccb240992896852487658865bad5ebdcd4 Mon Sep 17 00:00:00 2001 From: MMonik Date: Sun, 9 Apr 2017 10:43:50 +0300 Subject: [PATCH 274/291] Update README.md (#1606) --- spring-security-rest-full/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-security-rest-full/README.md b/spring-security-rest-full/README.md index faeeac1ec2..e7f543a407 100644 --- a/spring-security-rest-full/README.md +++ b/spring-security-rest-full/README.md @@ -29,6 +29,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com - [Changing Spring Model Parameters with Handler Interceptor](http://www.baeldung.com/spring-model-parameters-with-handler-interceptor) - [Introduction to Spring MVC HandlerInterceptor](http://www.baeldung.com/spring-mvc-handlerinterceptor) - [Using a Custom Spring MVC’s Handler Interceptor to Manage Sessions](http://www.baeldung.com/spring-mvc-custom-handler-interceptor) +- [Bootstrap a Web Application with Spring 4](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration) ### Build the Project ``` From 60332bb563609667c60cb77dd333e32aadb6b45b Mon Sep 17 00:00:00 2001 From: Tian Baoqiang Date: Sun, 9 Apr 2017 03:38:20 -0500 Subject: [PATCH 275/291] BAEL-451 (#1610) * BAEL-451 rest api test with JBehave * reformat pom * exclude live test from normal mvn test --- rest-testing/pom.xml | 318 +++++++++--------- .../baeldung/rest/jbehave/AbstractStory.java | 45 +++ .../rest/jbehave/GithubUserNotFoundSteps.java | 59 ++++ .../GithubUserNotFoundStoryLiveTest.java | 18 + .../GithubUserResponseMediaTypeSteps.java | 40 +++ ...hubUserResponseMediaTypeStoryLiveTest.java | 18 + .../GithubUserResponsePayloadSteps.java | 40 +++ ...ithubUserResponsePayloadStoryLiveTest.java | 18 + .../baeldung/rest/jbehave/IncreaseSteps.java | 34 ++ .../rest/jbehave/IncreaseStoryLiveTest.java | 38 +++ .../resources/github_user_not_found.story | 19 ++ .../github_user_response_mediatype.story | 13 + .../github_user_response_payload.story | 12 + .../src/test/resources/increase.story | 15 + 14 files changed, 532 insertions(+), 155 deletions(-) create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/AbstractStory.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundSteps.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundStoryLiveTest.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeSteps.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeStoryLiveTest.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadSteps.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadStoryLiveTest.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseSteps.java create mode 100644 rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseStoryLiveTest.java create mode 100644 rest-testing/src/test/resources/github_user_not_found.story create mode 100644 rest-testing/src/test/resources/github_user_response_mediatype.story create mode 100644 rest-testing/src/test/resources/github_user_response_payload.story create mode 100644 rest-testing/src/test/resources/increase.story diff --git a/rest-testing/pom.xml b/rest-testing/pom.xml index f7f94a49a6..746752133c 100644 --- a/rest-testing/pom.xml +++ b/rest-testing/pom.xml @@ -1,164 +1,171 @@ - 4.0.0 - com.baeldung - rest-testing - 0.1-SNAPSHOT + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.baeldung + rest-testing + 0.1-SNAPSHOT - rest-testing + rest-testing - + - + - - com.google.guava - guava - ${guava.version} - + + com.google.guava + guava + ${guava.version} + - - commons-io - commons-io - ${commons-io.version} - + + commons-io + commons-io + ${commons-io.version} + - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + - + - - org.apache.httpcomponents - httpclient - ${httpclient.version} - - - org.apache.httpcomponents - httpcore - ${httpcore.version} - + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + - + - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + - + - - org.slf4j - slf4j-api - ${org.slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - org.slf4j - jcl-over-slf4j - ${org.slf4j.version} - runtime - - - org.slf4j - log4j-over-slf4j - ${org.slf4j.version} - + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + org.slf4j + jcl-over-slf4j + ${org.slf4j.version} + runtime + + + org.slf4j + log4j-over-slf4j + ${org.slf4j.version} + - + - - junit - junit - ${junit.version} - test - + + junit + junit + ${junit.version} + test + - - org.hamcrest - hamcrest-core - ${org.hamcrest.version} - test - - - org.hamcrest - hamcrest-library - ${org.hamcrest.version} - test - + + org.hamcrest + hamcrest-core + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-library + ${org.hamcrest.version} + test + - - org.mockito - mockito-core - ${mockito.version} - test - - - com.github.tomakehurst - wiremock - ${wiremock.version} - test - + + org.mockito + mockito-core + ${mockito.version} + test + + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + - - info.cukes - cucumber-java - ${cucumber.version} - test - - - info.cukes - cucumber-junit - ${cucumber.version} - - + + info.cukes + cucumber-java + ${cucumber.version} + test + + + info.cukes + cucumber-junit + ${cucumber.version} + - - rest-testing - - - src/main/resources - true - - + + org.jbehave + jbehave-core + ${jbehave.version} + test + + - + + rest-testing + + + src/main/resources + true + + - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - + - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + **/*IntegrationTest.java **/*LiveTest.java - + - + - + @@ -177,10 +184,10 @@ **/*UnitTest.java + **/*LiveTest.java **/*IntegrationTest.java - **/*LiveTest.java @@ -195,37 +202,38 @@ - - - - 2.8.5 - - 1.7.21 - 1.1.7 + + + 2.8.5 - - 19.0 - 3.5 - 2.5 + + 1.7.21 + 1.1.7 - - 1.3 - 4.12 - 1.10.19 + + 19.0 + 3.5 + 2.5 + + + 1.3 + 4.12 + 1.10.19 2.9.0 1.2.5 2.4.1 - 4.4.5 - 4.5.2 + 4.4.5 + 4.5.2 + 4.1 - - 3.6.0 - 2.6 - 2.19.1 + + 3.6.0 + 2.6 + 2.19.1 - + \ No newline at end of file diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/AbstractStory.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/AbstractStory.java new file mode 100644 index 0000000000..ce3c98d07e --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/AbstractStory.java @@ -0,0 +1,45 @@ +package com.baeldung.rest.jbehave; + +import org.jbehave.core.configuration.Configuration; +import org.jbehave.core.configuration.MostUsefulConfiguration; +import org.jbehave.core.io.LoadFromClasspath; +import org.jbehave.core.junit.JUnitStories; +import org.jbehave.core.reporters.StoryReporterBuilder; +import org.jbehave.core.steps.InjectableStepsFactory; +import org.jbehave.core.steps.InstanceStepsFactory; + +import java.util.Arrays; +import java.util.List; + +import static org.jbehave.core.io.CodeLocations.codeLocationFromClass; +import static org.jbehave.core.reporters.Format.CONSOLE; + +/** + * @author aiet + */ +public abstract class AbstractStory extends JUnitStories { + + abstract String storyName(); + + @Override + public Configuration configuration() { + return new MostUsefulConfiguration() + .useStoryLoader(new LoadFromClasspath(this.getClass())) + .useStoryReporterBuilder(new StoryReporterBuilder() + .withCodeLocation(codeLocationFromClass(this.getClass())) + .withFormats(CONSOLE)); + } + + abstract Object stepInstance(); + + @Override + public InjectableStepsFactory stepsFactory() { + return new InstanceStepsFactory(configuration(), stepInstance()); + } + + @Override + protected List storyPaths() { + return Arrays.asList(storyName()); + } + +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundSteps.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundSteps.java new file mode 100644 index 0000000000..54d3b0b155 --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundSteps.java @@ -0,0 +1,59 @@ +package com.baeldung.rest.jbehave; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +import java.io.IOException; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.apache.http.HttpStatus.SC_NOT_FOUND; +import static org.junit.Assert.assertTrue; + +public class GithubUserNotFoundSteps { + + private String api; + private String nonExistentUser; + private int githubResponseCode; + + @Given("github user profile api") + public void givenGithubUserProfileApi() { + api = "https://api.github.com/users/%s"; + } + + @Given("a random non-existent username") + public void givenANonexistentUsername() { + nonExistentUser = randomAlphabetic(8); + } + + @When("I look for the random user via the api") + public void whenILookForTheUserViaTheApi() throws IOException { + githubResponseCode = getGithubUserProfile(api, nonExistentUser) + .getStatusLine() + .getStatusCode(); + } + + @When("I look for $user via the api") + public void whenILookForSomeNonExistentUserViaTheApi(String user) throws IOException { + githubResponseCode = getGithubUserProfile(api, user) + .getStatusLine() + .getStatusCode(); + } + + static HttpResponse getGithubUserProfile(String api, String username) throws IOException { + HttpUriRequest request = new HttpGet(String.format(api, username)); + return HttpClientBuilder + .create() + .build() + .execute(request); + } + + @Then("github respond: 404 not found") + public void thenGithubRespond404NotFound() { + assertTrue(SC_NOT_FOUND == githubResponseCode); + } +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundStoryLiveTest.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundStoryLiveTest.java new file mode 100644 index 0000000000..f681fb085a --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserNotFoundStoryLiveTest.java @@ -0,0 +1,18 @@ +package com.baeldung.rest.jbehave; + +/** + * @author aiet + */ +public class GithubUserNotFoundStoryLiveTest extends AbstractStory { + + @Override + String storyName() { + return "github_user_not_found.story"; + } + + @Override + Object stepInstance() { + return new GithubUserNotFoundSteps(); + } + +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeSteps.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeSteps.java new file mode 100644 index 0000000000..a1a9aceee5 --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeSteps.java @@ -0,0 +1,40 @@ +package com.baeldung.rest.jbehave; + +import org.apache.http.entity.ContentType; +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +import java.io.IOException; + +import static com.baeldung.rest.jbehave.GithubUserNotFoundSteps.getGithubUserProfile; +import static org.junit.Assert.assertEquals; + +public class GithubUserResponseMediaTypeSteps { + + private String api; + private String validUser; + private String mediaType; + + @Given("github user profile api") + public void givenGithubUserProfileApi() { + api = "https://api.github.com/users/%s"; + } + + @Given("a valid username") + public void givenAValidUsername() { + validUser = "eugenp"; + } + + @When("I look for the user via the api") + public void whenILookForTheUserViaTheApi() throws IOException { + mediaType = ContentType + .getOrDefault(getGithubUserProfile(api, validUser).getEntity()) + .getMimeType(); + } + + @Then("github respond data of type json") + public void thenGithubRespondDataOfTypeJson() { + assertEquals("application/json", mediaType); + } +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeStoryLiveTest.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeStoryLiveTest.java new file mode 100644 index 0000000000..c14f7aad75 --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponseMediaTypeStoryLiveTest.java @@ -0,0 +1,18 @@ +package com.baeldung.rest.jbehave; + +/** + * @author aiet + */ +public class GithubUserResponseMediaTypeStoryLiveTest extends AbstractStory { + + @Override + String storyName() { + return "github_user_response_mediatype.story"; + } + + @Override + Object stepInstance() { + return new GithubUserResponseMediaTypeSteps(); + } + +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadSteps.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadSteps.java new file mode 100644 index 0000000000..d9401a5d00 --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadSteps.java @@ -0,0 +1,40 @@ +package com.baeldung.rest.jbehave; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.baeldung.rest.GitHubUser; +import org.baeldung.rest.RetrieveUtil; +import org.hamcrest.Matchers; +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +import java.io.IOException; + +import static com.baeldung.rest.jbehave.GithubUserNotFoundSteps.getGithubUserProfile; +import static org.hamcrest.MatcherAssert.assertThat; + +public class GithubUserResponsePayloadSteps { + + private String api; + private GitHubUser resource; + + @Given("github user profile api") + public void givenGithubUserProfileApi() { + api = "https://api.github.com/users/%s"; + } + + @When("I look for $user via the api") + public void whenILookForEugenpViaTheApi(String user) throws IOException { + HttpResponse httpResponse = getGithubUserProfile(api, user); + resource = RetrieveUtil.retrieveResourceFromResponse(httpResponse, GitHubUser.class); + } + + @Then("github's response contains a 'login' payload same as $username") + public void thenGithubsResponseContainsAloginPayloadSameAsEugenp(String username) { + assertThat(username, Matchers.is(resource.getLogin())); + } + +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadStoryLiveTest.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadStoryLiveTest.java new file mode 100644 index 0000000000..cd7974869a --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/GithubUserResponsePayloadStoryLiveTest.java @@ -0,0 +1,18 @@ +package com.baeldung.rest.jbehave; + +/** + * @author aiet + */ +public class GithubUserResponsePayloadStoryLiveTest extends AbstractStory { + + @Override + String storyName() { + return "github_user_response_payload.story"; + } + + @Override + Object stepInstance() { + return new GithubUserResponsePayloadSteps(); + } + +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseSteps.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseSteps.java new file mode 100644 index 0000000000..3bc6fb2aa2 --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseSteps.java @@ -0,0 +1,34 @@ +package com.baeldung.rest.jbehave; + +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +import java.util.Random; + +import static org.junit.Assert.assertTrue; + +public class IncreaseSteps { + private int counter; + private int previousValue; + + @Given("a counter") + public void aCounter() { + } + + @Given("the counter has any integral value") + public void counterHasAnyIntegralValue() { + counter = new Random().nextInt(); + previousValue = counter; + } + + @When("the user increases the counter") + public void increasesTheCounter() { + counter++; + } + + @Then("the value of the counter must be 1 greater than previous value") + public void theValueOfTheCounterMustBe1Greater() { + assertTrue(1 == counter - previousValue); + } +} diff --git a/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseStoryLiveTest.java b/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseStoryLiveTest.java new file mode 100644 index 0000000000..9033dbfbdc --- /dev/null +++ b/rest-testing/src/test/java/com/baeldung/rest/jbehave/IncreaseStoryLiveTest.java @@ -0,0 +1,38 @@ +package com.baeldung.rest.jbehave; + +import org.jbehave.core.configuration.Configuration; +import org.jbehave.core.configuration.MostUsefulConfiguration; +import org.jbehave.core.io.LoadFromClasspath; +import org.jbehave.core.junit.JUnitStories; +import org.jbehave.core.reporters.StoryReporterBuilder; +import org.jbehave.core.steps.InjectableStepsFactory; +import org.jbehave.core.steps.InstanceStepsFactory; + +import java.util.Arrays; +import java.util.List; + +import static org.jbehave.core.io.CodeLocations.codeLocationFromClass; +import static org.jbehave.core.reporters.Format.CONSOLE; + +public class IncreaseStoryLiveTest extends JUnitStories { + + @Override + public Configuration configuration() { + return new MostUsefulConfiguration() + .useStoryLoader(new LoadFromClasspath(this.getClass())) + .useStoryReporterBuilder(new StoryReporterBuilder() + .withCodeLocation(codeLocationFromClass(this.getClass())) + .withFormats(CONSOLE)); + } + + @Override + public InjectableStepsFactory stepsFactory() { + return new InstanceStepsFactory(configuration(), new IncreaseSteps()); + } + + @Override + protected List storyPaths() { + return Arrays.asList("increase.story"); + } + +} diff --git a/rest-testing/src/test/resources/github_user_not_found.story b/rest-testing/src/test/resources/github_user_not_found.story new file mode 100644 index 0000000000..1ab6920eee --- /dev/null +++ b/rest-testing/src/test/resources/github_user_not_found.story @@ -0,0 +1,19 @@ +Meta: + +Narrative: +As a user +I want to look up a non-existent user's profile on github +So that I can be sure that the username can not be found on github + +Scenario: when a user checks a non-existent user on github, github would respond 'not found' + +Given github user profile api +And a random non-existent username +When I look for the random user via the api +Then github respond: 404 not found + +When I look for eugenp1 via the api +Then github respond: 404 not found + +When I look for eugenp2 via the api +Then github respond: 404 not found diff --git a/rest-testing/src/test/resources/github_user_response_mediatype.story b/rest-testing/src/test/resources/github_user_response_mediatype.story new file mode 100644 index 0000000000..7c4a0b9e2d --- /dev/null +++ b/rest-testing/src/test/resources/github_user_response_mediatype.story @@ -0,0 +1,13 @@ +Meta: + +Narrative: +As a user +I want to look up a valid user's profile on github +So that I can know that github responds data of type json + +Scenario: when a user checks a valid user's profile on github, github would respond json data + +Given github user profile api +And a valid username +When I look for the user via the api +Then github respond data of type json \ No newline at end of file diff --git a/rest-testing/src/test/resources/github_user_response_payload.story b/rest-testing/src/test/resources/github_user_response_payload.story new file mode 100644 index 0000000000..788b43eba6 --- /dev/null +++ b/rest-testing/src/test/resources/github_user_response_payload.story @@ -0,0 +1,12 @@ +Meta: + +Narrative: +As a user +I want to look up a valid user's profile on github +So that I can know the login payload should be the same as username + +Scenario: when a user checks a valid user's profile on github, github's response json should include a login payload with the same username + +Given github user profile api +When I look for eugenp via the api +Then github's response contains a 'login' payload same as eugenp diff --git a/rest-testing/src/test/resources/increase.story b/rest-testing/src/test/resources/increase.story new file mode 100644 index 0000000000..fef91298bc --- /dev/null +++ b/rest-testing/src/test/resources/increase.story @@ -0,0 +1,15 @@ +JBehave Story - An increase test + +Meta: + +Narrative: +As a user +I want to increase a counter +So that I can have the counter's value increase by 1 + +Scenario: when a user increases a counter, its value is increased by 1 + +Given a counter +And the counter has any integral value +When the user increases the counter +Then the value of the counter must be 1 greater than previous value \ No newline at end of file From a5de78c2b21737448ee7aed4f7a4449e2cbc60a5 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Sun, 9 Apr 2017 12:23:57 +0200 Subject: [PATCH 276/291] Bael 766 flink (#1533) * BAEL-756 code for flink article * reorder * simpler wordCount example * BAEL-766 changes according to PR * BAEL-766 change datasource to dataset * BAEL-766 add sorting example * BAEL-766 add simple streaming example * one missing change to dataSet * windowing example * add window example * add dependency explicitly * add plugin * add surefire plugin, change neme of the test to *IntegrationTest --- libraries/pom.xml | 42 ++++ .../java/com/baeldung/flink/LineSplitter.java | 20 ++ .../java/com/baeldung/flink/WordCount.java | 20 ++ .../flink/WordCountIntegrationTest.java | 196 ++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 libraries/src/main/java/com/baeldung/flink/LineSplitter.java create mode 100644 libraries/src/main/java/com/baeldung/flink/WordCount.java create mode 100644 libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 0f33c42dc4..a200fe8350 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -20,6 +20,31 @@ 1.8 + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.felix + maven-bundle-plugin + 3.3.0 + maven-plugin + + + + true + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + **/*IntegrationTest.java + **/*LiveTest.java + + + @@ -92,6 +117,21 @@ commons-io ${commons.io.version} + + org.apache.flink + flink-core + ${flink.version} + + + org.apache.flink + flink-java + ${flink.version} + + + org.apache.flink + flink-test-utils_2.10 + ${flink.version} + @@ -107,6 +147,8 @@ 9.4.2.v20170220 4.5.3 2.5 + 1.2.0 + 2.19.1 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/flink/LineSplitter.java b/libraries/src/main/java/com/baeldung/flink/LineSplitter.java new file mode 100644 index 0000000000..8deeeb01c4 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/flink/LineSplitter.java @@ -0,0 +1,20 @@ +package com.baeldung.flink; + +import org.apache.flink.api.common.functions.FlatMapFunction; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.util.Collector; + +import java.util.stream.Stream; + +@SuppressWarnings("serial") +public class LineSplitter implements FlatMapFunction> { + + @Override + public void flatMap(String value, Collector> out) { + + String[] tokens = value.toLowerCase().split("\\W+"); + Stream.of(tokens) + .filter(t -> t.length() > 0) + .forEach(token -> out.collect(new Tuple2<>(token, 1))); + } +} \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/flink/WordCount.java b/libraries/src/main/java/com/baeldung/flink/WordCount.java new file mode 100644 index 0000000000..ab109bdbce --- /dev/null +++ b/libraries/src/main/java/com/baeldung/flink/WordCount.java @@ -0,0 +1,20 @@ +package com.baeldung.flink; + +import org.apache.flink.api.java.DataSet; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.aggregation.Aggregations; +import org.apache.flink.api.java.tuple.Tuple2; + +import java.util.List; + +public class WordCount { + + public static DataSet> startWordCount(ExecutionEnvironment env, List lines) throws Exception { + DataSet text = env.fromCollection(lines); + + return text.flatMap(new LineSplitter()) + .groupBy(0) + .aggregate(Aggregations.SUM, 1); + + } +} \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java new file mode 100644 index 0000000000..91a75c78ba --- /dev/null +++ b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java @@ -0,0 +1,196 @@ +package com.baeldung.flink; + +import org.apache.flink.api.common.functions.ReduceFunction; +import org.apache.flink.api.common.operators.Order; +import org.apache.flink.api.java.DataSet; +import org.apache.flink.api.java.ExecutionEnvironment; +import org.apache.flink.api.java.functions.KeySelector; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.streaming.api.datastream.DataStream; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor; +import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows; +import org.apache.flink.streaming.api.windowing.time.Time; +import org.junit.Test; + +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class WordCountIntegrationTest { + final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); + + @Test + public void givenDataSet_whenExecuteWordCount_thenReturnWordCount() throws Exception { + //given + List lines = Arrays.asList("This is a first sentence", "This is a second sentence with a one word"); + + //when + DataSet> result = WordCount.startWordCount(env, lines); + + //then + List> collect = result.collect(); + assertThat(collect.size()).isEqualTo(9); + assertThat(collect.contains(new Tuple2<>("a", 3))).isTrue(); + assertThat(collect.contains(new Tuple2<>("sentence", 2))).isTrue(); + assertThat(collect.contains(new Tuple2<>("word", 1))).isTrue(); + assertThat(collect.contains(new Tuple2<>("is", 2))).isTrue(); + assertThat(collect.contains(new Tuple2<>("this", 2))).isTrue(); + assertThat(collect.contains(new Tuple2<>("second", 1))).isTrue(); + assertThat(collect.contains(new Tuple2<>("first", 1))).isTrue(); + } + + @Test + public void givenListOfAmounts_whenUseMapReduce_thenSumAmountsThatAreOnlyAboveThreshold() throws Exception { + //given + DataSet amounts = env.fromElements(1, 29, 40, 50); + int threshold = 30; + + //when + List collect = amounts + .filter(a -> a > threshold) + .reduce((ReduceFunction) (integer, t1) -> integer + t1) + .collect(); + + //then + assertThat(collect.get(0)).isEqualTo(90); + } + + @Test + public void givenDataSetOfComplexObjects_whenMapToGetOneField_thenReturnedListHaveProperElements() throws Exception { + //given + DataSet personDataSource = env.fromCollection(Arrays.asList(new Person(23, "Tom"), new Person(75, "Michael"))); + + //when + List ages = personDataSource.map(p -> p.age).collect(); + + //then + assertThat(ages.size()).isEqualTo(2); + assertThat(ages.containsAll(Arrays.asList(23, 75))).isTrue(); + + } + + @Test + public void givenDataSet_whenSortItByOneField_thenShouldReturnSortedDataSet() throws Exception { + //given + Tuple2 secondPerson = new Tuple2<>(4, "Tom"); + Tuple2 thirdPerson = new Tuple2<>(5, "Scott"); + Tuple2 fourthPerson = new Tuple2<>(200, "Michael"); + Tuple2 firstPerson = new Tuple2<>(1, "Jack"); + DataSet> transactions = env.fromElements(fourthPerson, secondPerson, + thirdPerson, firstPerson); + + + //when + List> sorted = transactions + .sortPartition(new IdKeySelectorTransaction(), Order.ASCENDING) + .collect(); + + //then + assertThat(sorted.size()).isEqualTo(4); + assertThat(sorted.get(0)).isEqualTo(firstPerson); + assertThat(sorted.get(1)).isEqualTo(secondPerson); + assertThat(sorted.get(2)).isEqualTo(thirdPerson); + assertThat(sorted.get(3)).isEqualTo(fourthPerson); + + } + + + @Test + public void giveTwoDataSets_whenJoinUsingId_thenProduceJoinedData() throws Exception { + //given + Tuple3 address = new Tuple3<>(1, "5th Avenue", "London"); + DataSet> addresses = env.fromElements(address); + + Tuple2 firstTransaction = new Tuple2<>(1, "Transaction_1"); + DataSet> transactions = + env.fromElements(firstTransaction, new Tuple2<>(12, "Transaction_2")); + + + //when + List, Tuple3>> joined = + transactions.join(addresses) + .where(new IdKeySelectorTransaction()) + .equalTo(new IdKeySelectorAddress()) + .collect(); + + //then + assertThat(joined.size()).isEqualTo(1); + assertThat(joined.contains(new Tuple2<>(firstTransaction, address))); + + } + + @Test + public void givenStreamOfEvents_whenProcessEvents_thenShouldPrintResultsOnSinkOperation() throws Exception { + //given + final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + DataStream text + = env.fromElements("This is a first sentence", "This is a second sentence with a one word"); + + + SingleOutputStreamOperator upperCase = text.map(String::toUpperCase); + + upperCase.print(); + + //when + env.execute(); + } + + + @Test + public void givenStreamOfEvents_whenProcessEvents_thenShouldApplyWindowingOnTransformation() throws Exception { + //given + final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + SingleOutputStreamOperator> windowed = env.fromElements( + new Tuple2<>(16, ZonedDateTime.now().plusMinutes(25).toInstant().getEpochSecond()), + new Tuple2<>(15, ZonedDateTime.now().plusMinutes(2).toInstant().getEpochSecond()) + ).assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor>(Time.seconds(20)) { + @Override + public long extractTimestamp(Tuple2 element) { + return element.f1 * 1000; + } + }); + + SingleOutputStreamOperator> reduced = windowed + .windowAll(TumblingEventTimeWindows.of(Time.seconds(5))) + .maxBy(0, true); + + reduced.print(); + + //when + env.execute(); + } + + + private static class IdKeySelectorTransaction implements KeySelector, Integer> { + @Override + public Integer getKey(Tuple2 value) { + return value.f0; + } + } + + private static class IdKeySelectorAddress implements KeySelector, Integer> { + @Override + public Integer getKey(Tuple3 value) { + return value.f0; + } + } + + private static class Person { + private final int age; + private final String name; + + private Person(int age, String name) { + this.age = age; + this.name = name; + } + } + +} \ No newline at end of file From cc276589ec33e686cb00a3449d26d693d136f6c0 Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Sun, 9 Apr 2017 20:38:30 +0200 Subject: [PATCH 277/291] fix integration test (#1615) * upgrade to spring boot 1.5.2 * add full update to REST API * modify ratings controller * upgrade herold * fix integration test * fix integration test * minor fix * fix integration test * fix integration test * minor cleanup --- spring-boot/src/main/resources/schema.sql | 2 ++ .../org/baeldung/SpringBootApplicationIntegrationTest.java | 2 +- spring-boot/src/test/resources/import.sql | 2 +- .../test/resources/persistence-generic-entity.properties | 6 +++--- .../web/controller/GreetControllerIntegrationTest.java | 3 ++- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/spring-boot/src/main/resources/schema.sql b/spring-boot/src/main/resources/schema.sql index 27859c1652..4cd345c762 100644 --- a/spring-boot/src/main/resources/schema.sql +++ b/spring-boot/src/main/resources/schema.sql @@ -1,3 +1,5 @@ +drop table if exists USERS; + create table USERS( ID int not null AUTO_INCREMENT, NAME varchar(100) not null, diff --git a/spring-boot/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java index 87c59a4662..4ce0678bdd 100644 --- a/spring-boot/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java +++ b/spring-boot/src/test/java/org/baeldung/SpringBootApplicationIntegrationTest.java @@ -63,4 +63,4 @@ public class SpringBootApplicationIntegrationTest { mockMvc.perform(MockMvcRequestBuilders.get("/entity/findbyversion").header("Version", "1.0.0")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(contentType)) .andExpect(jsonPath("$.id", equalTo(1))); } -} +} \ No newline at end of file diff --git a/spring-boot/src/test/resources/import.sql b/spring-boot/src/test/resources/import.sql index a382410271..9095b9468c 100644 --- a/spring-boot/src/test/resources/import.sql +++ b/spring-boot/src/test/resources/import.sql @@ -1 +1 @@ -Insert into Foo values(1,'Foo_Name'); \ No newline at end of file +--insert into Foo values(1,'Foo_Name'); \ No newline at end of file diff --git a/spring-boot/src/test/resources/persistence-generic-entity.properties b/spring-boot/src/test/resources/persistence-generic-entity.properties index c60e7488b6..b19304cb1f 100644 --- a/spring-boot/src/test/resources/persistence-generic-entity.properties +++ b/spring-boot/src/test/resources/persistence-generic-entity.properties @@ -1,8 +1,8 @@ jdbc.driverClassName=org.h2.Driver jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 -jdbc.username=sa -jdbc.password=sa +jdbc.user=sa +jdbc.pass=sa hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.show_sql=true -hibernate.hbm2ddl.auto=create-drop \ No newline at end of file +hibernate.hbm2ddl.auto=create-drop diff --git a/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java b/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java index ca8c37175e..b628228b7e 100644 --- a/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java +++ b/spring-mvc-java/src/test/java/com/baeldung/web/controller/GreetControllerIntegrationTest.java @@ -21,10 +21,11 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import com.baeldung.spring.web.config.ApplicationConfig; +import com.baeldung.spring.web.config.WebConfig; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration -@ContextConfiguration(classes = { ApplicationConfig.class }) +@ContextConfiguration(classes = { ApplicationConfig.class, WebConfig.class }) public class GreetControllerIntegrationTest { @Autowired From a826e70c2311e9d4943e3233322d2c1b81418670 Mon Sep 17 00:00:00 2001 From: maibin Date: Mon, 10 Apr 2017 05:19:49 +0200 Subject: [PATCH 278/291] Jenetics library (#1601) --- algorithms/.gitignore | 1 + algorithms/pom.xml | 5 ++ .../algorithms/ga/jenetics/Knapsack.java | 47 ++++++++++ .../algorithms/ga/jenetics/KnapsackFF.java | 25 ++++++ .../algorithms/ga/jenetics/KnapsackItem.java | 34 ++++++++ .../ga/jenetics/SimpleGeneticAlgorithm.java | 33 +++++++ .../ga/jenetics/SpringsteenProblem.java | 86 +++++++++++++++++++ .../ga/jenetics/SpringsteenRecord.java | 24 ++++++ .../algorithms/ga/jenetics/SubsetSum.java | 66 ++++++++++++++ .../ga/jenetics/TravelingSalesman.java | 67 +++++++++++++++ 10 files changed, 388 insertions(+) create mode 100644 algorithms/.gitignore create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java diff --git a/algorithms/.gitignore b/algorithms/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/algorithms/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/algorithms/pom.xml b/algorithms/pom.xml index 529af19686..884c804d13 100644 --- a/algorithms/pom.xml +++ b/algorithms/pom.xml @@ -31,6 +31,11 @@ ${lombok.version} provided + + io.jenetics + jenetics + 3.7.0 + diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java new file mode 100644 index 0000000000..cc99ccf204 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/Knapsack.java @@ -0,0 +1,47 @@ +package com.baeldung.algorithms.ga.jenetics; + +import static org.jenetics.engine.EvolutionResult.toBestPhenotype; +import static org.jenetics.engine.limit.bySteadyFitness; + +import java.util.stream.Stream; + +import org.jenetics.BitChromosome; +import org.jenetics.BitGene; +import org.jenetics.Mutator; +import org.jenetics.Phenotype; +import org.jenetics.RouletteWheelSelector; +import org.jenetics.SinglePointCrossover; +import org.jenetics.TournamentSelector; +import org.jenetics.engine.Engine; +import org.jenetics.engine.EvolutionStatistics; + +//The main class. +public class Knapsack { + + public static void main(String[] args) { + int nItems = 15; + double ksSize = nItems * 100.0 / 3.0; + + KnapsackFF ff = new KnapsackFF(Stream.generate(KnapsackItem::random) + .limit(nItems) + .toArray(KnapsackItem[]::new), ksSize); + + Engine engine = Engine.builder(ff, BitChromosome.of(nItems, 0.5)) + .populationSize(500) + .survivorsSelector(new TournamentSelector<>(5)) + .offspringSelector(new RouletteWheelSelector<>()) + .alterers(new Mutator<>(0.115), new SinglePointCrossover<>(0.16)) + .build(); + + EvolutionStatistics statistics = EvolutionStatistics.ofNumber(); + + Phenotype best = engine.stream() + .limit(bySteadyFitness(7)) + .limit(100) + .peek(statistics) + .collect(toBestPhenotype()); + + System.out.println(statistics); + System.out.println(best); + } +} \ No newline at end of file diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java new file mode 100644 index 0000000000..e3e06d301a --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackFF.java @@ -0,0 +1,25 @@ +package com.baeldung.algorithms.ga.jenetics; + +import java.util.function.Function; + +import org.jenetics.BitChromosome; +import org.jenetics.BitGene; +import org.jenetics.Genotype; + +public class KnapsackFF implements Function, Double> { + private KnapsackItem[] items; + private double size; + + public KnapsackFF(KnapsackItem[] items, double size) { + this.items = items; + this.size = size; + } + + @Override + public Double apply(Genotype gt) { + KnapsackItem sum = ((BitChromosome) gt.getChromosome()).ones() + .mapToObj(i -> items[i]) + .collect(KnapsackItem.toSum()); + return sum.size <= this.size ? sum.value : 0; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java new file mode 100644 index 0000000000..876df0ba25 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/KnapsackItem.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.ga.jenetics; + +import java.util.Random; +import java.util.stream.Collector; + +import org.jenetics.util.RandomRegistry; + +public class KnapsackItem { + + public double size; + public double value; + + public KnapsackItem(double size, double value) { + this.size = size; + this.value = value; + } + + protected static KnapsackItem random() { + Random r = RandomRegistry.getRandom(); + return new KnapsackItem(r.nextDouble() * 100, r.nextDouble() * 100); + } + + protected static Collector toSum() { + return Collector.of(() -> new double[2], (a, b) -> { + a[0] += b.size; + a[1] += b.value; + } , (a, b) -> { + a[0] += b[0]; + a[1] += b[1]; + return a; + } , r -> new KnapsackItem(r[0], r[1])); + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java new file mode 100644 index 0000000000..845e11b349 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SimpleGeneticAlgorithm.java @@ -0,0 +1,33 @@ +package com.baeldung.algorithms.ga.jenetics; + +import org.jenetics.BitChromosome; +import org.jenetics.BitGene; +import org.jenetics.Genotype; +import org.jenetics.engine.Engine; +import org.jenetics.engine.EvolutionResult; +import org.jenetics.util.Factory; + +public class SimpleGeneticAlgorithm { + + private static Integer eval(Genotype gt) { + return gt.getChromosome() + .as(BitChromosome.class) + .bitCount(); + } + + public static void main(String[] args) { + Factory> gtf = Genotype.of(BitChromosome.of(10, 0.5)); + System.out.println("Before the evolution:\n" + gtf); + + Engine engine = Engine.builder(SimpleGeneticAlgorithm::eval, gtf) + .build(); + + Genotype result = engine.stream() + .limit(500) + .collect(EvolutionResult.toBestGenotype()); + + System.out.println("After the evolution:\n" + result); + + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java new file mode 100644 index 0000000000..55f2f7af0a --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenProblem.java @@ -0,0 +1,86 @@ +package com.baeldung.algorithms.ga.jenetics; + +import static java.util.Objects.requireNonNull; + +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.jenetics.BitGene; +import org.jenetics.engine.Codec; +import org.jenetics.engine.Engine; +import org.jenetics.engine.EvolutionResult; +import org.jenetics.engine.Problem; +import org.jenetics.engine.codecs; +import org.jenetics.util.ISeq; + +public class SpringsteenProblem implements Problem, BitGene, Double> { + + private ISeq records; + private double maxPricePerUniqueSong; + + public SpringsteenProblem(ISeq records, double maxPricePerUniqueSong) { + this.records = requireNonNull(records); + this.maxPricePerUniqueSong = maxPricePerUniqueSong; + } + + @Override + public Function, Double> fitness() { + return SpringsteenRecords -> { + double cost = SpringsteenRecords.stream() + .mapToDouble(r -> r.price) + .sum(); + + int uniqueSongCount = SpringsteenRecords.stream() + .flatMap(r -> r.songs.stream()) + .collect(Collectors.toSet()) + .size(); + + double pricePerUniqueSong = cost / uniqueSongCount; + + return pricePerUniqueSong <= maxPricePerUniqueSong ? uniqueSongCount : 0.0; + }; + } + + @Override + public Codec, BitGene> codec() { + return codecs.ofSubSet(records); + } + + public static void main(String[] args) { + double maxPricePerUniqueSong = 2.5; + + SpringsteenProblem springsteen = new SpringsteenProblem( + ISeq.of(new SpringsteenRecord("SpringsteenRecord1", 25, ISeq.of("Song1", "Song2", "Song3", "Song4", "Song5", "Song6")), new SpringsteenRecord("SpringsteenRecord2", 15, ISeq.of("Song2", "Song3", "Song4", "Song5", "Song6", "Song7")), + new SpringsteenRecord("SpringsteenRecord3", 35, ISeq.of("Song5", "Song6", "Song7", "Song8", "Song9", "Song10")), new SpringsteenRecord("SpringsteenRecord4", 17, ISeq.of("Song9", "Song10", "Song12", "Song4", "Song13", "Song14")), + new SpringsteenRecord("SpringsteenRecord5", 29, ISeq.of("Song1", "Song2", "Song13", "Song14", "Song15", "Song16")), new SpringsteenRecord("SpringsteenRecord6", 5, ISeq.of("Song18", "Song20", "Song30", "Song40"))), + maxPricePerUniqueSong); + + Engine engine = Engine.builder(springsteen) + .build(); + + ISeq result = springsteen.codec() + .decoder() + .apply(engine.stream() + .limit(10) + .collect(EvolutionResult.toBestGenotype())); + + double cost = result.stream() + .mapToDouble(r -> r.price) + .sum(); + + int uniqueSongCount = result.stream() + .flatMap(r -> r.songs.stream()) + .collect(Collectors.toSet()) + .size(); + + double pricePerUniqueSong = cost / uniqueSongCount; + + System.out.println("Overall cost: " + cost); + System.out.println("Unique songs: " + uniqueSongCount); + System.out.println("Cost per song: " + pricePerUniqueSong); + System.out.println("Records: " + result.map(r -> r.name) + .toString(", ")); + + } + +} \ No newline at end of file diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java new file mode 100644 index 0000000000..b49709e7f5 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SpringsteenRecord.java @@ -0,0 +1,24 @@ +package com.baeldung.algorithms.ga.jenetics; + +import static java.util.Objects.requireNonNull; + +import org.jenetics.util.ISeq; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class SpringsteenRecord { + + String name; + double price; + ISeq songs; + + public SpringsteenRecord(String name, double price, ISeq songs) { + this.name = requireNonNull(name); + this.price = price; + this.songs = requireNonNull(songs); + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java new file mode 100644 index 0000000000..db1e11239f --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/SubsetSum.java @@ -0,0 +1,66 @@ +package com.baeldung.algorithms.ga.jenetics; + +import static java.util.Objects.requireNonNull; + +import java.util.Random; +import java.util.function.Function; + +import org.jenetics.EnumGene; +import org.jenetics.Mutator; +import org.jenetics.PartiallyMatchedCrossover; +import org.jenetics.Phenotype; +import org.jenetics.engine.Codec; +import org.jenetics.engine.Engine; +import org.jenetics.engine.EvolutionResult; +import org.jenetics.engine.Problem; +import org.jenetics.engine.codecs; +import org.jenetics.engine.limit; +import org.jenetics.util.ISeq; +import org.jenetics.util.LCG64ShiftRandom; + +public class SubsetSum implements Problem, EnumGene, Integer> { + + private ISeq basicSet; + private int size; + + public SubsetSum(ISeq basicSet, int size) { + this.basicSet = requireNonNull(basicSet); + this.size = size; + } + + @Override + public Function, Integer> fitness() { + return subset -> Math.abs(subset.stream() + .mapToInt(Integer::intValue) + .sum()); + } + + @Override + public Codec, EnumGene> codec() { + return codecs.ofSubSet(basicSet, size); + } + + public static SubsetSum of(int n, int k, Random random) { + return new SubsetSum(random.doubles() + .limit(n) + .mapToObj(d -> (int) ((d - 0.5) * n)) + .collect(ISeq.toISeq()), k); + } + + public static void main(String[] args) { + SubsetSum problem = of(500, 15, new LCG64ShiftRandom(101010)); + + Engine, Integer> engine = Engine.builder(problem) + .minimizing() + .maximalPhenotypeAge(5) + .alterers(new PartiallyMatchedCrossover<>(0.4), new Mutator<>(0.3)) + .build(); + + Phenotype, Integer> result = engine.stream() + .limit(limit.bySteadyFitness(55)) + .collect(EvolutionResult.toBestPhenotype()); + + System.out.print(result); + } + +} \ No newline at end of file diff --git a/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java new file mode 100644 index 0000000000..80ede0f8c5 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/ga/jenetics/TravelingSalesman.java @@ -0,0 +1,67 @@ +package com.baeldung.algorithms.ga.jenetics; + +import static java.lang.Math.PI; +import static java.lang.Math.abs; +import static java.lang.Math.sin; +import static org.jenetics.engine.EvolutionResult.toBestPhenotype; +import static org.jenetics.engine.limit.bySteadyFitness; + +import java.util.stream.IntStream; + +import org.jenetics.EnumGene; +import org.jenetics.Optimize; +import org.jenetics.PartiallyMatchedCrossover; +import org.jenetics.Phenotype; +import org.jenetics.SwapMutator; +import org.jenetics.engine.Engine; +import org.jenetics.engine.EvolutionStatistics; +import org.jenetics.engine.codecs; + +public class TravelingSalesman { + + private static final int STOPS = 50; + private static final double[][] ADJACENCE = matrix(STOPS); + + private static double[][] matrix(int stops) { + final double radius = 100.0; + double[][] matrix = new double[stops][stops]; + + for (int i = 0; i < stops; ++i) { + for (int j = 0; j < stops; ++j) { + matrix[i][j] = chord(stops, abs(i - j), radius); + } + } + return matrix; + } + + private static double chord(int stops, int i, double r) { + return 2.0 * r * abs(sin(PI * i / stops)); + } + + private static double dist(final int[] path) { + return IntStream.range(0, STOPS) + .mapToDouble(i -> ADJACENCE[path[i]][path[(i + 1) % STOPS]]) + .sum(); + } + + public static void main(String[] args) { + final Engine, Double> engine = Engine.builder(TravelingSalesman::dist, codecs.ofPermutation(STOPS)) + .optimize(Optimize.MINIMUM) + .maximalPhenotypeAge(11) + .populationSize(500) + .alterers(new SwapMutator<>(0.2), new PartiallyMatchedCrossover<>(0.35)) + .build(); + + final EvolutionStatistics statistics = EvolutionStatistics.ofNumber(); + + final Phenotype, Double> best = engine.stream() + .limit(bySteadyFitness(15)) + .limit(250) + .peek(statistics) + .collect(toBestPhenotype()); + + System.out.println(statistics); + System.out.println(best); + } + +} From a78a4dc544cfe4e00b3ab71d2d51c5d6bb4b254c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20G=C3=B3mez?= Date: Sun, 9 Apr 2017 23:21:44 -0600 Subject: [PATCH 279/291] Update on README (#1619) * Add project for hibernate immutable article Add Event entity Add hibernate configuration file Add hibernateutil for configuration Add test to match snippets from article * Update master * Add articles to README --- core-java/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core-java/README.md b/core-java/README.md index 096ff51df6..e75701717f 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -11,7 +11,9 @@ - [Converting between a List and a Set in Java](http://www.baeldung.com/convert-list-to-set-and-set-to-list) - [Convert a Map to an Array, List or Set in Java](http://www.baeldung.com/convert-map-values-to-array-list-set) - [Java – Write to File](http://www.baeldung.com/java-write-to-file) -- [Java - Convert File to InputStream] (http://www.baeldung.com/convert-file-to-input-stream) +- [Java - Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream) +- [Java – Random Long, Float, Integer and Double](http://www.baeldung.com/java-generate-random-long-float-integer-double) +- [Java – Generate Random String](http://www.baeldung.com/java-random-string) - [Java Scanner](http://www.baeldung.com/java-scanner) - [Java Timer](http://www.baeldung.com/java-timer-and-timertask) - [Java – Byte Array to Writer](http://www.baeldung.com/java-convert-byte-array-to-writer) @@ -86,4 +88,5 @@ - [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) - [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) - [Guide to Java 8 Comparator.comparing()](http://www.baeldung.com/java-8-comparator-comparing) - +- [Removing all nulls from a List in Java](http://www.baeldung.com/java-remove-nulls-from-list) +- [Removing all duplicates from a List in Java](http://www.baeldung.com/java-remove-duplicates-from-list) From 4e560091eaf0033d1d52a58659fdc00c2e7b5550 Mon Sep 17 00:00:00 2001 From: Doha2012 Date: Mon, 10 Apr 2017 11:48:47 +0200 Subject: [PATCH 280/291] minor cleanup (#1618) * upgrade to spring boot 1.5.2 * add full update to REST API * modify ratings controller * upgrade herold * fix integration test * fix integration test * minor fix * fix integration test * fix integration test * minor cleanup * minor cleanup --- .../data-flow-server/pom.xml | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/spring-cloud-data-flow/data-flow-server/pom.xml b/spring-cloud-data-flow/data-flow-server/pom.xml index 1ed2d4fb74..bd3b4ab150 100644 --- a/spring-cloud-data-flow/data-flow-server/pom.xml +++ b/spring-cloud-data-flow/data-flow-server/pom.xml @@ -77,39 +77,4 @@ - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - - From 1a288b591186c7b8699a096b4ef5ac40b9080c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Melo?= Date: Mon, 10 Apr 2017 11:44:16 +0100 Subject: [PATCH 281/291] Code for Avoiding ConcurrentModificationException when iterating and removing (#1617) --- core-java/README.md | 2 + .../ConcurrentModificationExceptionTest.java | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 core-java/src/test/java/com/baeldung/java/collections/ConcurrentModificationExceptionTest.java diff --git a/core-java/README.md b/core-java/README.md index e75701717f..a7c8b0e855 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -88,5 +88,7 @@ - [Java Primitive Conversions](http://www.baeldung.com/java-primitive-conversions) - [Java Money and the Currency API](http://www.baeldung.com/java-money-and-currency) - [Guide to Java 8 Comparator.comparing()](http://www.baeldung.com/java-8-comparator-comparing) +- [Avoiding ConcurrentModificationException when iterating and removing](http://www.baeldung.com/avoiding-concurrentmodificationexception-when-iterating-and-removing) - [Removing all nulls from a List in Java](http://www.baeldung.com/java-remove-nulls-from-list) - [Removing all duplicates from a List in Java](http://www.baeldung.com/java-remove-duplicates-from-list) + diff --git a/core-java/src/test/java/com/baeldung/java/collections/ConcurrentModificationExceptionTest.java b/core-java/src/test/java/com/baeldung/java/collections/ConcurrentModificationExceptionTest.java new file mode 100644 index 0000000000..100d25ab8d --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java/collections/ConcurrentModificationExceptionTest.java @@ -0,0 +1,82 @@ +package com.baeldung.java.collections; + +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; + +import static java.util.Arrays.asList; +import static org.testng.Assert.assertEquals; + +public class ConcurrentModificationExceptionTest { + @Test + public void changingContentWithSetDoesNotThrowConcurrentModificationException() throws Exception { + ArrayList array = new ArrayList<>(asList(0, "one", 2, "three")); + + for (Object item : array) { + array.set(3, 3); + } + } + + @Test + public void removingElementUsingIteratorAPI() throws Exception { + List originalList = new ArrayList<>(asList("zero", "one", "two", "three")); + + Iterator iterator = originalList.iterator(); + + while (iterator.hasNext()) { + String next = iterator.next(); + if (Objects.equals(next, "one")) iterator.remove(); + } + + assertEquals(originalList, asList("zero", "two", "three")); + } + + @Test + public void modifyingContentAndIteratingUsingListIteratorAPI() throws Exception { + List originalList = new ArrayList<>(asList("zero", "one", "two", "three")); + + ListIterator iterator = originalList.listIterator(); + + while (iterator.hasNext()) { + String next = iterator.next(); + if (Objects.equals(next, "one")) { + iterator.set("another"); + } + + if (Objects.equals(next, "two")) { + iterator.remove(); + } + + if (Objects.equals(next, "three")) { + iterator.add("four"); + } + } + + assertEquals(originalList, asList("zero", "another", "three", "four")); + } + + @Test + public void removingElementUsingCopyAndListAPI() throws Exception { + List originalList = new ArrayList<>(asList("zero", "one", "two", "three")); + + List listCopy = new ArrayList<>(originalList); + + for (String next : listCopy) { + if (Objects.equals(next, "one")) originalList.remove(originalList.indexOf(next) - 1); + } + + assertEquals(originalList, asList("one", "two", "three")); + } + + @Test + public void copyOnWriteList() throws Exception { + List originalList = new CopyOnWriteArrayList<>(asList("zero", "one", "two", "three")); + + for (String next : originalList) { + if (Objects.equals(next, "one")) originalList.remove(originalList.indexOf(next) - 1); + } + + assertEquals(originalList, asList("one", "two", "three")); + } +} From 34aa697a026cbef02bb9633ee6833508803e74a2 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Mon, 10 Apr 2017 13:36:35 +0200 Subject: [PATCH 282/291] remove unused module (#1628) --- pom.xml | 1 - spring-mvc-no-xml/.gitignore | 13 -- spring-mvc-no-xml/README.md | 9 - spring-mvc-no-xml/pom.xml | 175 ------------------ .../java/org/baeldung/servlet/WebAppNew.java | 42 ----- .../java/org/baeldung/servlet/WebAppOld.java | 23 --- .../org/baeldung/spring/ClientWebConfig.java | 39 ---- .../src/main/resources/logback.xml | 20 -- .../src/main/resources/webSecurityConfig.xml | 37 ---- .../src/main/webapp/WEB-INF/mvc-servlet.xml | 6 - .../src/main/webapp/WEB-INF/view/sample.jsp | 7 - .../src/main/webapp/WEB-INF/web_old.xml | 43 ----- .../src/test/resources/.gitignore | 13 -- 13 files changed, 428 deletions(-) delete mode 100644 spring-mvc-no-xml/.gitignore delete mode 100644 spring-mvc-no-xml/README.md delete mode 100644 spring-mvc-no-xml/pom.xml delete mode 100644 spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppNew.java delete mode 100644 spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppOld.java delete mode 100644 spring-mvc-no-xml/src/main/java/org/baeldung/spring/ClientWebConfig.java delete mode 100644 spring-mvc-no-xml/src/main/resources/logback.xml delete mode 100644 spring-mvc-no-xml/src/main/resources/webSecurityConfig.xml delete mode 100644 spring-mvc-no-xml/src/main/webapp/WEB-INF/mvc-servlet.xml delete mode 100644 spring-mvc-no-xml/src/main/webapp/WEB-INF/view/sample.jsp delete mode 100644 spring-mvc-no-xml/src/main/webapp/WEB-INF/web_old.xml delete mode 100644 spring-mvc-no-xml/src/test/resources/.gitignore diff --git a/pom.xml b/pom.xml index b21d656772..1a11bd055f 100644 --- a/pom.xml +++ b/pom.xml @@ -153,7 +153,6 @@ spring-mvc-email spring-mvc-forms spring-mvc-java - spring-mvc-no-xml spring-mvc-tiles spring-mvc-velocity spring-mvc-web-vs-initializer diff --git a/spring-mvc-no-xml/.gitignore b/spring-mvc-no-xml/.gitignore deleted file mode 100644 index 83c05e60c8..0000000000 --- a/spring-mvc-no-xml/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.class - -#folders# -/target -/neoDb* -/data -/src/main/webapp/WEB-INF/classes -*/META-INF/* - -# Packaged files # -*.jar -*.war -*.ear \ No newline at end of file diff --git a/spring-mvc-no-xml/README.md b/spring-mvc-no-xml/README.md deleted file mode 100644 index 208cb35f78..0000000000 --- a/spring-mvc-no-xml/README.md +++ /dev/null @@ -1,9 +0,0 @@ -========= - -## Spring MVC with NO XML Configuration Example Project - -###The Course -The "REST With Spring" Classes: http://bit.ly/restwithspring - -### Relevant Articles: -- diff --git a/spring-mvc-no-xml/pom.xml b/spring-mvc-no-xml/pom.xml deleted file mode 100644 index 4437661199..0000000000 --- a/spring-mvc-no-xml/pom.xml +++ /dev/null @@ -1,175 +0,0 @@ - - 4.0.0 - com.baeldung - 0.1-SNAPSHOT - spring-mvc-no-xml - - spring-mvc-no-xml - war - - - - - - - org.springframework - spring-web - ${org.springframework.version} - - - org.springframework - spring-webmvc - ${org.springframework.version} - - - - - - javax.servlet - javax.servlet-api - ${javax.servlet-api.version} - provided - - - - javax.servlet - jstl - ${jstl.version} - runtime - - - - - - org.slf4j - slf4j-api - ${org.slf4j.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - - org.slf4j - jcl-over-slf4j - ${org.slf4j.version} - - - - org.slf4j - log4j-over-slf4j - ${org.slf4j.version} - - - - - - junit - junit - ${junit.version} - test - - - - org.hamcrest - hamcrest-core - ${org.hamcrest.version} - test - - - org.hamcrest - hamcrest-library - ${org.hamcrest.version} - test - - - - org.mockito - mockito-core - ${mockito.version} - test - - - - - - spring-mvc-no-xml - - - src/main/resources - true - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - 1.8 - 1.8 - - - - - org.apache.maven.plugins - maven-war-plugin - ${maven-war-plugin.version} - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - - - - - - - - - - - - - - - 4.3.4.RELEASE - - - 1.7.21 - 1.1.7 - - - 1.3 - 4.12 - 1.10.19 - - 3.1.0 - 1.2 - - 4.4.5 - 4.5.2 - - 2.9.0 - - - 3.6.0 - 2.6 - 2.19.1 - 2.7 - 1.6.1 - - - - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppNew.java b/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppNew.java deleted file mode 100644 index 2422f2110a..0000000000 --- a/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppNew.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.baeldung.servlet; - -import javax.servlet.ServletRegistration.Dynamic; - -import org.baeldung.spring.ClientWebConfig; -import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; - -/** - * Further reading:
- * - http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config
- * - http://geowarin.wordpress.com/2013/01/23/complete-example-of-a-spring-mvc-3-2-project/
- * - http://www.objectpartners.com/2012/01/16/introduction-to-servlet-3-0/
- */ -public class WebAppNew extends AbstractAnnotationConfigDispatcherServletInitializer { - - public WebAppNew() { - super(); - } - - // API - - @Override - protected Class[] getRootConfigClasses() { - return null; - } - - @Override - protected Class[] getServletConfigClasses() { - return new Class[] { ClientWebConfig.class }; - } - - @Override - protected String[] getServletMappings() { - return new String[] { "/" }; - } - - @Override - protected void customizeRegistration(final Dynamic registration) { - super.customizeRegistration(registration); - } - -} diff --git a/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppOld.java b/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppOld.java deleted file mode 100644 index 85c67c094d..0000000000 --- a/spring-mvc-no-xml/src/main/java/org/baeldung/servlet/WebAppOld.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.baeldung.servlet; - -// public class WebApp implements WebApplicationInitializer { -// -// public WebApp() { -// super(); -// } -// -// // API -// -// @Override -// public void onStartup(final ServletContext servletContext) throws ServletException { -// final AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext(); -// root.setServletContext(servletContext); -// root.scan("org.baeldung.spring"); -// root.refresh(); -// -// final Dynamic servlet = servletContext.addServlet("mvc", new DispatcherServlet(root)); -// servlet.setLoadOnStartup(1); -// servlet.addMapping("/"); -// } -// -// } diff --git a/spring-mvc-no-xml/src/main/java/org/baeldung/spring/ClientWebConfig.java b/spring-mvc-no-xml/src/main/java/org/baeldung/spring/ClientWebConfig.java deleted file mode 100644 index eaefb0984b..0000000000 --- a/spring-mvc-no-xml/src/main/java/org/baeldung/spring/ClientWebConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.baeldung.spring; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import org.springframework.web.servlet.view.InternalResourceViewResolver; -import org.springframework.web.servlet.view.JstlView; - -@EnableWebMvc -@Configuration -public class ClientWebConfig extends WebMvcConfigurerAdapter { - - public ClientWebConfig() { - super(); - } - - // API - - @Override - public void addViewControllers(final ViewControllerRegistry registry) { - super.addViewControllers(registry); - - registry.addViewController("/sample.html"); - } - - @Bean - public ViewResolver viewResolver() { - final InternalResourceViewResolver bean = new InternalResourceViewResolver(); - - bean.setViewClass(JstlView.class); - bean.setPrefix("/WEB-INF/view/"); - bean.setSuffix(".jsp"); - - return bean; - } -} \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/resources/logback.xml b/spring-mvc-no-xml/src/main/resources/logback.xml deleted file mode 100644 index 1146dade63..0000000000 --- a/spring-mvc-no-xml/src/main/resources/logback.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - web - %date [%thread] %-5level %logger{36} - %message%n - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/resources/webSecurityConfig.xml b/spring-mvc-no-xml/src/main/resources/webSecurityConfig.xml deleted file mode 100644 index febac349b0..0000000000 --- a/spring-mvc-no-xml/src/main/resources/webSecurityConfig.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/webapp/WEB-INF/mvc-servlet.xml b/spring-mvc-no-xml/src/main/webapp/WEB-INF/mvc-servlet.xml deleted file mode 100644 index 4ba9642448..0000000000 --- a/spring-mvc-no-xml/src/main/webapp/WEB-INF/mvc-servlet.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/webapp/WEB-INF/view/sample.jsp b/spring-mvc-no-xml/src/main/webapp/WEB-INF/view/sample.jsp deleted file mode 100644 index 7cc14b5dcd..0000000000 --- a/spring-mvc-no-xml/src/main/webapp/WEB-INF/view/sample.jsp +++ /dev/null @@ -1,7 +0,0 @@ - - - - -

This is the body of the sample view

- - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/main/webapp/WEB-INF/web_old.xml b/spring-mvc-no-xml/src/main/webapp/WEB-INF/web_old.xml deleted file mode 100644 index e2f52148c3..0000000000 --- a/spring-mvc-no-xml/src/main/webapp/WEB-INF/web_old.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - Spring MVC No XML Application - - - - contextClass - - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - - contextConfigLocation - org.baeldung.spring - - - - org.springframework.web.context.ContextLoaderListener - - - - - mvc - org.springframework.web.servlet.DispatcherServlet - 1 - - - mvc - / - - - - - - index.html - - - \ No newline at end of file diff --git a/spring-mvc-no-xml/src/test/resources/.gitignore b/spring-mvc-no-xml/src/test/resources/.gitignore deleted file mode 100644 index 83c05e60c8..0000000000 --- a/spring-mvc-no-xml/src/test/resources/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.class - -#folders# -/target -/neoDb* -/data -/src/main/webapp/WEB-INF/classes -*/META-INF/* - -# Packaged files # -*.jar -*.war -*.ear \ No newline at end of file From 3fd20f6479023dad0f54dfcf49e3716abc630933 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Mon, 10 Apr 2017 15:10:33 +0200 Subject: [PATCH 283/291] Bael 770 jetty (#1629) * BAEL-770 add jetty simple test case * BAEL-770 jetty async and blocking servlets * BAEL-766 reorder * increment version * configuration thread pool --- libraries/pom.xml | 23 +++++++++++++++++++ .../java/com/baeldung/jetty/JettyServer.java | 9 +++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libraries/pom.xml b/libraries/pom.xml index a200fe8350..80ec0edfea 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -117,6 +117,26 @@ commons-io ${commons.io.version} + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-io + commons-io + ${commons.io.version} + org.apache.flink flink-core @@ -144,6 +164,9 @@ 3.6.2 1.5.0 3.1.0 + 9.4.3.v20170317 + 4.5.3 + 2.5 9.4.2.v20170220 4.5.3 2.5 diff --git a/libraries/src/main/java/com/baeldung/jetty/JettyServer.java b/libraries/src/main/java/com/baeldung/jetty/JettyServer.java index 1365de866a..1033a7266d 100644 --- a/libraries/src/main/java/com/baeldung/jetty/JettyServer.java +++ b/libraries/src/main/java/com/baeldung/jetty/JettyServer.java @@ -4,6 +4,7 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.util.thread.QueuedThreadPool; public class JettyServer { @@ -11,7 +12,13 @@ public class JettyServer { public void start() throws Exception { - server = new Server(); + int maxThreads = 100; + int minThreads = 10; + int idleTimeout = 120; + + QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, minThreads, idleTimeout); + + server = new Server(threadPool); ServerConnector connector = new ServerConnector(server); connector.setPort(8090); server.setConnectors(new Connector[]{connector}); From b5e4c4e3e73ffa6978fee1492ae33f4bf0efd85c Mon Sep 17 00:00:00 2001 From: Jesus Boadas Date: Mon, 10 Apr 2017 12:39:37 -0400 Subject: [PATCH 284/291] Converters, Listeners and Validators in Java EE 7 (#1630) --- jee7/pom.xml | 49 +++++++++++++++- .../com/baeldung/convListVal/ConvListVal.java | 56 +++++++++++++++++++ .../com/baeldung/convListVal/MyListener.java | 21 +++++++ .../javaeeannotations/AccountServlet.java | 2 +- .../BankAppServletContextListener.java | 2 +- .../javaeeannotations/LogInFilter.java | 2 +- .../UploadCustomerDocumentsServlet.java | 2 +- jee7/src/main/webapp/ConvListVal.xhtml | 50 +++++++++++++++++ .../jaxws/EmployeeServiceLiveTest.java | 3 +- 9 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 jee7/src/main/java/com/baeldung/convListVal/ConvListVal.java create mode 100644 jee7/src/main/java/com/baeldung/convListVal/MyListener.java create mode 100644 jee7/src/main/webapp/ConvListVal.xhtml diff --git a/jee7/pom.xml b/jee7/pom.xml index 26d433df78..addb586b74 100644 --- a/jee7/pom.xml +++ b/jee7/pom.xml @@ -7,7 +7,6 @@ jee7 1.0-SNAPSHOT JavaEE 7 Arquillian Archetype Sample - war 1.8 @@ -28,6 +27,7 @@ 3.6.0 2.6 + 2.19.1 @@ -43,6 +43,13 @@ import pom + + org.jboss.arquillian.extension + arquillian-drone-bom + 2.0.1.Final + pom + import + @@ -65,6 +72,13 @@ arquillian-junit-container test + + org.jboss.arquillian.graphene + graphene-webdriver + 2.1.0.Final + pom + test + com.jayway.awaitility awaitility @@ -85,6 +99,37 @@ test + + com.sun.faces + jsf-api + 2.2.14 + + + com.sun.faces + jsf-impl + 2.2.14 + + + javax.servlet + jstl + 1.2 + + + javax.servlet + javax.servlet-api + 3.1.0 + + + javax.servlet.jsp + jsp-api + 2.2 + provided + + + taglibs + standard + 1.1.2 + @@ -167,6 +212,7 @@ + maven-dependency-plugin @@ -206,6 +252,7 @@ + diff --git a/jee7/src/main/java/com/baeldung/convListVal/ConvListVal.java b/jee7/src/main/java/com/baeldung/convListVal/ConvListVal.java new file mode 100644 index 0000000000..245c69f2bb --- /dev/null +++ b/jee7/src/main/java/com/baeldung/convListVal/ConvListVal.java @@ -0,0 +1,56 @@ +package com.baeldung.convListVal; + +import java.util.Date; + +import javax.faces.bean.ManagedBean; + +@ManagedBean +public class ConvListVal { + + private Integer age; + private Double average; + private Date myDate; + private String name; + private String surname; + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Double getAverage() { + return average; + } + + public void setAverage(Double average) { + this.average = average; + } + + public Date getMyDate() { + return myDate; + } + + public void setMyDate(Date myDate) { + this.myDate = myDate; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + +} diff --git a/jee7/src/main/java/com/baeldung/convListVal/MyListener.java b/jee7/src/main/java/com/baeldung/convListVal/MyListener.java new file mode 100644 index 0000000000..784bddd59a --- /dev/null +++ b/jee7/src/main/java/com/baeldung/convListVal/MyListener.java @@ -0,0 +1,21 @@ +package com.baeldung.convListVal; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.faces.event.AbortProcessingException; +import javax.faces.event.ValueChangeEvent; +import javax.faces.event.ValueChangeListener; + +public class MyListener implements ValueChangeListener { + + private static final Logger LOG = Logger.getLogger(MyListener.class.getName()); + @Override + public void processValueChange(ValueChangeEvent event) throws AbortProcessingException { + if (event.getNewValue() != null) { + LOG.log(Level.INFO, "\tNew Value:{0}", event.getNewValue()); + } + + } + +} diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java index a8ed74984b..aa7e490eed 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/AccountServlet.java @@ -1,4 +1,4 @@ -package com.baeldung.javaeeannotations; +package com.baeldung.javaeeannotations.JavaEEAnnotationsSample.src.main.java.com.baeldung.javaeeannotations; import java.io.IOException; import java.io.PrintWriter; diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java index ee1b624cd1..dc9a91d059 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/BankAppServletContextListener.java @@ -1,4 +1,4 @@ -package com.baeldung.javaeeannotations; +package com.baeldung.javaeeannotations.JavaEEAnnotationsSample.src.main.java.com.baeldung.javaeeannotations; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java index 5ee420f6a2..bfe1a39377 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/LogInFilter.java @@ -1,4 +1,4 @@ -package com.baeldung.javaeeannotations; +package com.baeldung.javaeeannotations.JavaEEAnnotationsSample.src.main.java.com.baeldung.javaeeannotations; import java.io.IOException; diff --git a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java index 28922dba46..6945f663bb 100644 --- a/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java +++ b/jee7/src/main/java/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/java/com/baeldung/javaeeannotations/UploadCustomerDocumentsServlet.java @@ -1,4 +1,4 @@ -package com.baeldung.javaeeannotations; +package com.baeldung.javaeeannotations.JavaEEAnnotationsSample.src.main.java.com.baeldung.javaeeannotations; import java.io.IOException; import java.io.PrintWriter; diff --git a/jee7/src/main/webapp/ConvListVal.xhtml b/jee7/src/main/webapp/ConvListVal.xhtml new file mode 100644 index 0000000000..e5425e87a5 --- /dev/null +++ b/jee7/src/main/webapp/ConvListVal.xhtml @@ -0,0 +1,50 @@ + + + + + Converters, Listeners and Validators + + +

Testing converters

+ + + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + + + +
+ +
+
+ diff --git a/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java index 5311b3c5fe..4429703468 100644 --- a/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java +++ b/jee7/src/test/java/com/baeldung/jaxws/EmployeeServiceLiveTest.java @@ -1,4 +1,4 @@ -package com.baeldung.jaxws; +/*package com.baeldung.jaxws; import static org.junit.Assert.assertEquals; @@ -108,3 +108,4 @@ public class EmployeeServiceLiveTest { } } +*/ \ No newline at end of file From 0acc76d0dc237fcb5e3be60edc39e772e8e227d6 Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Mon, 10 Apr 2017 21:21:05 -0500 Subject: [PATCH 285/291] BAEL-735 README update (#1623) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README * BAEL-415: Custom Scope * BAEL-415: Custom Scope - renamed classes to reflect TenantScope * README file updates for BAEL-723, BAEL-763, and BAEL-415 * BAEL-735: README --- spring-boot/README.MD | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot/README.MD b/spring-boot/README.MD index beb780ec3c..1874f621b5 100644 --- a/spring-boot/README.MD +++ b/spring-boot/README.MD @@ -16,4 +16,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners) - [Guide to Internationalization in Spring Boot](http://www.baeldung.com/spring-boot-internationalization) - [Create a Custom FailureAnalyzer with Spring Boot](http://www.baeldung.com/spring-boot-failure-analyzer) +- [Configuring Separate Spring DataSource for Tests](http://www.baeldung.com/spring-testing-separate-data-source) From c75daff854b52e3710fbb4c16d5e2262bd053ba6 Mon Sep 17 00:00:00 2001 From: Grzegorz Piwowarek Date: Tue, 11 Apr 2017 08:45:52 +0200 Subject: [PATCH 286/291] Refactor Mockito snippets (#1616) --- .../baeldung/mockito/MockitoConfigExamplesTest.java | 13 +++---------- spring-all/pom.xml | 2 +- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/mockito/src/test/java/org/baeldung/mockito/MockitoConfigExamplesTest.java b/mockito/src/test/java/org/baeldung/mockito/MockitoConfigExamplesTest.java index de6e7fca72..5050a2d6bc 100644 --- a/mockito/src/test/java/org/baeldung/mockito/MockitoConfigExamplesTest.java +++ b/mockito/src/test/java/org/baeldung/mockito/MockitoConfigExamplesTest.java @@ -2,8 +2,6 @@ package org.baeldung.mockito; import org.junit.Test; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.hamcrest.Matchers.equalTo; @@ -69,7 +67,7 @@ public class MockitoConfigExamplesTest { } @Test - public final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMetehodIsCalled() { + public final void whenMockMethodCallIsConfiguredToCallTheRealMethod_thenRealMethodIsCalled() { final MyList listMock = Mockito.mock(MyList.class); when(listMock.size()).thenCallRealMethod(); @@ -77,14 +75,9 @@ public class MockitoConfigExamplesTest { } @Test - public final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMetehodIsCalled() { + public final void whenMockMethodCallIsConfiguredWithCustomAnswer_thenRealMethodIsCalled() { final MyList listMock = Mockito.mock(MyList.class); - doAnswer(new Answer() { - @Override - public final String answer(final InvocationOnMock invocation) { - return "Always the same"; - } - }).when(listMock).get(anyInt()); + doAnswer(invocation -> "Always the same").when(listMock).get(anyInt()); final String element = listMock.get(1); assertThat(element, is(equalTo("Always the same"))); diff --git a/spring-all/pom.xml b/spring-all/pom.xml index eb7a573c89..1b12d7e42c 100644 --- a/spring-all/pom.xml +++ b/spring-all/pom.xml @@ -302,7 +302,7 @@ 3.1.3 3.4 3.6.1 - 6.4.0 + 6.4.0 From 3fb4e03a49fcc26ed3558848f8c86a1f6445d51f Mon Sep 17 00:00:00 2001 From: Diane Duan Date: Tue, 11 Apr 2017 16:11:58 +0800 Subject: [PATCH 287/291] BAEL-640: Guide to Mathematical Operations with Guava (BDD naming) (#1599) * Guava IntMath tests * Guava DoubleMath test * break down testDoubleMath() * bdd ut naming * bdd ut naming 2 * break down round unit test * rename unit tests --- .../org/baeldung/guava/GuavaMathTest.java | 288 ++++++++++-------- 1 file changed, 158 insertions(+), 130 deletions(-) diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java b/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java index d0c551032c..b8e13f0650 100644 --- a/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java +++ b/guava/src/test/java/org/baeldung/guava/GuavaMathTest.java @@ -1,167 +1,195 @@ package org.baeldung.guava; -import com.google.common.math.DoubleMath; -import com.google.common.math.IntMath; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.*; import java.math.BigInteger; import java.math.RoundingMode; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import com.google.common.math.DoubleMath; +import com.google.common.math.IntMath; public class GuavaMathTest { - @Test - public void testIntMathAdd() { - try { - IntMath.checkedAdd(Integer.MAX_VALUE, 1); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } + @Test(expected = ArithmeticException.class) + public void whenSumOverflow_thenThrowException() { + IntMath.checkedAdd(Integer.MAX_VALUE, 1); + } - try { - IntMath.checkedAdd(Integer.MIN_VALUE, -1); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } - - int result1 = IntMath.checkedAdd(2, 1); - assertThat(result1, equalTo(3)); - - int result2 = IntMath.saturatedAdd(Integer.MAX_VALUE, 100); - assertThat(result2, equalTo(Integer.MAX_VALUE)); - - int result3 = IntMath.saturatedAdd(Integer.MIN_VALUE, -100); - assertThat(result3, equalTo(Integer.MIN_VALUE)); + @Test(expected = ArithmeticException.class) + public void whenSumUnderflow_thenThrowException() { + IntMath.checkedAdd(Integer.MIN_VALUE, -1); } @Test - public void testIntMathSubtract() { - try { - IntMath.checkedSubtract(Integer.MIN_VALUE, 1); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } - - try { - IntMath.checkedSubtract(Integer.MAX_VALUE, -1); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - }; - - int result1 = IntMath.checkedSubtract(200, 100); - assertThat(result1, equalTo(100)); - - int result2 = IntMath.saturatedSubtract(Integer.MIN_VALUE, 1); - assertThat(result2, equalTo(Integer.MIN_VALUE)); - - int result3 = IntMath.saturatedSubtract(Integer.MAX_VALUE, -1); - assertThat(result3, equalTo(Integer.MAX_VALUE)); + public void should_calculate_sum() { + int result = IntMath.checkedAdd(2, 1); + assertThat(result, equalTo(3)); } @Test - public void testIntMathMultiply() { - try { - IntMath.checkedMultiply(Integer.MAX_VALUE, 2); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } - - try { - IntMath.checkedMultiply(Integer.MIN_VALUE, 2); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } - - int result1 = IntMath.checkedMultiply(21, 3); - assertThat(result1, equalTo(63)); - - int result2 = IntMath.saturatedMultiply(Integer.MAX_VALUE, 2); - assertThat(result2, equalTo(Integer.MAX_VALUE)); - - int result3 = IntMath.saturatedMultiply(Integer.MIN_VALUE, 2); - assertThat(result3, equalTo(Integer.MIN_VALUE)); + public void whenSumOverflow_thenReturnMaxInteger() { + int result = IntMath.saturatedAdd(Integer.MAX_VALUE, 100); + assertThat(result, equalTo(Integer.MAX_VALUE)); } @Test - public void testIntMathPow() { - try { - IntMath.checkedPow(Integer.MAX_VALUE, 2); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } + public void whenSumUnderflow_thenReturnMinInteger() { + int result = IntMath.saturatedAdd(Integer.MIN_VALUE, -100); + assertThat(result, equalTo(Integer.MIN_VALUE)); + } - try { - IntMath.checkedPow(Integer.MIN_VALUE, 3); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } + @Test(expected = ArithmeticException.class) + public void whenDifferenceOverflow_thenThrowException() { + IntMath.checkedSubtract(Integer.MAX_VALUE, -1); + } - int result1 = IntMath.saturatedPow(3, 3); - assertThat(result1, equalTo(27)); - - int result2 = IntMath.saturatedPow(Integer.MAX_VALUE, 2); - assertThat(result2, equalTo(Integer.MAX_VALUE)); - - int result3 = IntMath.saturatedPow(Integer.MIN_VALUE, 3); - assertThat(result3, equalTo(Integer.MIN_VALUE)); + @Test(expected = ArithmeticException.class) + public void whenDifferenceUnderflow_thenThrowException() { + IntMath.checkedSubtract(Integer.MIN_VALUE, 1); } @Test - public void testIntMathRound() { + public void should_calculate_difference() { + int result = IntMath.checkedSubtract(200, 100); + assertThat(result, equalTo(100)); + } + + @Test + public void whenDifferenceOverflow_thenReturnMaxInteger() { + int result = IntMath.saturatedSubtract(Integer.MAX_VALUE, -1); + assertThat(result, equalTo(Integer.MAX_VALUE)); + } + + @Test + public void whenDifferenceUnderflow_thenReturnMinInteger() { + int result = IntMath.saturatedSubtract(Integer.MIN_VALUE, 1); + assertThat(result, equalTo(Integer.MIN_VALUE)); + } + + @Test(expected = ArithmeticException.class) + public void whenProductOverflow_thenThrowException() { + IntMath.checkedMultiply(Integer.MAX_VALUE, 2); + } + + @Test(expected = ArithmeticException.class) + public void whenProductUnderflow_thenThrowException() { + IntMath.checkedMultiply(Integer.MIN_VALUE, 2); + } + + @Test + public void should_calculate_product() { + int result = IntMath.checkedMultiply(21, 3); + assertThat(result, equalTo(63)); + } + + @Test + public void whenProductOverflow_thenReturnMaxInteger() { + int result = IntMath.saturatedMultiply(Integer.MAX_VALUE, 2); + assertThat(result, equalTo(Integer.MAX_VALUE)); + } + + @Test + public void whenProductUnderflow_thenReturnMinInteger() { + int result = IntMath.saturatedMultiply(Integer.MIN_VALUE, 2); + assertThat(result, equalTo(Integer.MIN_VALUE)); + } + + @Test(expected = ArithmeticException.class) + public void whenPowerOverflow_thenThrowException() { + IntMath.checkedPow(Integer.MAX_VALUE, 2); + } + + @Test(expected = ArithmeticException.class) + public void whenPowerUnderflow_thenThrowException() { + IntMath.checkedPow(Integer.MIN_VALUE, 3); + } + + @Test + public void should_calculate_power() { + int result = IntMath.saturatedPow(3, 3); + assertThat(result, equalTo(27)); + } + + @Test + public void whenPowerOverflow_thenReturnMaxInteger() { + int result = IntMath.saturatedPow(Integer.MAX_VALUE, 2); + assertThat(result, equalTo(Integer.MAX_VALUE)); + } + + @Test + public void whenPowerUnderflow_thenReturnMinInteger() { + int result = IntMath.saturatedPow(Integer.MIN_VALUE, 3); + assertThat(result, equalTo(Integer.MIN_VALUE)); + } + + @Test + public void should_round_divide_result() { int result1 = IntMath.divide(3, 2, RoundingMode.DOWN); assertThat(result1, equalTo(1)); + int result2 = IntMath.divide(3, 2, RoundingMode.UP); assertThat(result2, equalTo(2)); - - int result3 = IntMath.log2(5, RoundingMode.FLOOR); - assertThat(result3, equalTo(2)); - int result4 = IntMath.log2(5, RoundingMode.CEILING); - assertThat(result4, equalTo(3)); - - int result5 = IntMath.log10(11, RoundingMode.HALF_UP); - assertThat(result5, equalTo(1)); - - int result6 = IntMath.sqrt(4, RoundingMode.UNNECESSARY); - assertThat(result6, equalTo(2)); - try { - IntMath.sqrt(5, RoundingMode.UNNECESSARY); - assertTrue(false); - } catch (ArithmeticException e) { - assertTrue(true); - } } @Test - public void testIntMathAdditionalFunctions() { - int result1 = IntMath.gcd(15, 20); - assertThat(result1, equalTo(5)); + public void should_round_log2_result() { + int result1 = IntMath.log2(5, RoundingMode.FLOOR); + assertThat(result1, equalTo(2)); - int result2 = IntMath.mod(8, 3); - assertThat(result2, equalTo(2)); + int result2 = IntMath.log2(5, RoundingMode.CEILING); + assertThat(result2, equalTo(3)); + } - boolean result3 = IntMath.isPowerOfTwo(8); - assertTrue(result3); - boolean result4 = IntMath.isPowerOfTwo(9); - assertFalse(result4); + @Test + public void should_round_log10_result() { + int result = IntMath.log10(11, RoundingMode.HALF_UP); + assertThat(result, equalTo(1)); + } - int result5 = IntMath.factorial(4); - assertThat(result5, equalTo(24)); + @Test + public void should_round_sqrt_result() { + int result = IntMath.sqrt(4, RoundingMode.UNNECESSARY); + assertThat(result, equalTo(2)); + } - int result6 = IntMath.binomial(7, 3); - assertThat(result6, equalTo(35)); + @Test(expected = ArithmeticException.class) + public void whenNeedRounding_thenThrowException() { + IntMath.sqrt(5, RoundingMode.UNNECESSARY); + } + + @Test + public void should_calculate_gcd() { + int result = IntMath.gcd(15, 20); + assertThat(result, equalTo(5)); + } + + @Test + public void should_calculate_mod() { + int result = IntMath.mod(8, 3); + assertThat(result, equalTo(2)); + } + + @Test + public void should_test_if_is_power_of_two() { + boolean result1 = IntMath.isPowerOfTwo(8); + assertTrue(result1); + + boolean result2 = IntMath.isPowerOfTwo(9); + assertFalse(result2); + } + + @Test + public void should_calculate_factorial() { + int result = IntMath.factorial(4); + assertThat(result, equalTo(24)); + } + + @Test + public void should_calculate_binomial() { + int result = IntMath.binomial(7, 3); + assertThat(result, equalTo(35)); } @Test From 6cafa3d5a7d92f21121b16c7f6ade0c043200973 Mon Sep 17 00:00:00 2001 From: Tehreem Date: Tue, 11 Apr 2017 13:38:29 +0500 Subject: [PATCH 288/291] Spring Cloud Zookeeper Updated (#1626) * Spring Cloud Zookeeper * Spring Cloud Zookeeper Updated * Spring Cloud Zookeeper Updated --- spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml | 5 ----- .../spring/cloud/greeting/GreetingApplication.java | 7 ------- .../spring/cloud/greeting/GreetingController.java | 12 +++--------- .../spring/cloud/greeting/HelloWorldClient.java | 8 -------- .../cloud/helloworld/HelloWorldController.java | 1 - 5 files changed, 3 insertions(+), 30 deletions(-) diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml b/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml index 4d19741210..de76c86a24 100644 --- a/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/pom.xml @@ -35,11 +35,6 @@ spring-cloud-starter-feign 1.2.5.RELEASE - - org.springframework.boot - spring-boot-starter-thymeleaf - 1.5.2.RELEASE - junit junit diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java index e8beebeadf..8a1662999b 100644 --- a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingApplication.java @@ -5,16 +5,9 @@ */ package com.baeldung.spring.cloud.greeting; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.netflix.feign.EnableFeignClients; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableDiscoveryClient diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java index d701a2c762..d98e22f822 100644 --- a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/GreetingController.java @@ -6,16 +6,11 @@ package com.baeldung.spring.cloud.greeting; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.netflix.feign.EnableFeignClients; -import org.springframework.stereotype.Controller; - -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -@Controller +@RestController public class GreetingController { @Autowired @@ -23,10 +18,9 @@ public class GreetingController { @RequestMapping(value = "/get-greeting", method = RequestMethod.GET) - public String greeting(Model model) { + public String greeting() { - model.addAttribute("greeting", helloWorldClient.HelloWorld()); - return "greeting-view"; + return helloWorldClient.HelloWorld(); } diff --git a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java index d2b91ca715..c56cb1907a 100644 --- a/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java +++ b/spring-cloud/spring-cloud-zookeeper/Greeting/src/main/java/com/baeldung/spring/cloud/greeting/HelloWorldClient.java @@ -5,8 +5,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @@ -36,12 +34,6 @@ public class HelloWorldClient { String HelloWorld(); } - /** - * Initiate call to Validation. - * - * @param name - * @return the response - */ public String HelloWorld() { return theClient.HelloWorld(); } diff --git a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java index d5ea84de19..9048e6bed8 100644 --- a/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java +++ b/spring-cloud/spring-cloud-zookeeper/HelloWorld/src/main/java/com/baeldung/spring/cloud/helloworld/HelloWorldController.java @@ -5,7 +5,6 @@ */ package com.baeldung.spring.cloud.helloworld; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; From 3286018dd2535f70950c96fa3289e1418dd33fd2 Mon Sep 17 00:00:00 2001 From: Tomasz Lelek Date: Tue, 11 Apr 2017 13:08:11 +0200 Subject: [PATCH 289/291] Bael 766 flink (#1632) * BAEL-756 code for flink article * reorder * simpler wordCount example * BAEL-766 changes according to PR * BAEL-766 change datasource to dataset * BAEL-766 add sorting example * BAEL-766 add simple streaming example * one missing change to dataSet * windowing example * add window example * add dependency explicitly * add plugin * add surefire plugin, change neme of the test to *IntegrationTest * fluent assertions --- libraries/pom.xml | 15 +++++++++++++ .../flink/WordCountIntegrationTest.java | 22 +++++-------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libraries/pom.xml b/libraries/pom.xml index 80ec0edfea..1d908c453a 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -152,6 +152,21 @@ flink-test-utils_2.10 ${flink.version} + + org.apache.flink + flink-core + ${flink.version} + + + org.apache.flink + flink-java + ${flink.version} + + + org.apache.flink + flink-test-utils_2.10 + ${flink.version} + diff --git a/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java index 91a75c78ba..3190debef8 100644 --- a/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java +++ b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java @@ -1,6 +1,5 @@ package com.baeldung.flink; -import org.apache.flink.api.common.functions.ReduceFunction; import org.apache.flink.api.common.operators.Order; import org.apache.flink.api.java.DataSet; import org.apache.flink.api.java.ExecutionEnvironment; @@ -35,14 +34,10 @@ public class WordCountIntegrationTest { //then List> collect = result.collect(); - assertThat(collect.size()).isEqualTo(9); - assertThat(collect.contains(new Tuple2<>("a", 3))).isTrue(); - assertThat(collect.contains(new Tuple2<>("sentence", 2))).isTrue(); - assertThat(collect.contains(new Tuple2<>("word", 1))).isTrue(); - assertThat(collect.contains(new Tuple2<>("is", 2))).isTrue(); - assertThat(collect.contains(new Tuple2<>("this", 2))).isTrue(); - assertThat(collect.contains(new Tuple2<>("second", 1))).isTrue(); - assertThat(collect.contains(new Tuple2<>("first", 1))).isTrue(); + assertThat(collect).containsExactlyInAnyOrder( + new Tuple2<>("a", 3), new Tuple2<>("sentence", 2), new Tuple2<>("word", 1), + new Tuple2<>("is", 2), new Tuple2<>("this", 2), new Tuple2<>("second", 1), + new Tuple2<>("first", 1), new Tuple2<>("with", 1), new Tuple2<>("one", 1)); } @Test @@ -54,7 +49,7 @@ public class WordCountIntegrationTest { //when List collect = amounts .filter(a -> a > threshold) - .reduce((ReduceFunction) (integer, t1) -> integer + t1) + .reduce((integer, t1) -> integer + t1) .collect(); //then @@ -92,12 +87,7 @@ public class WordCountIntegrationTest { .collect(); //then - assertThat(sorted.size()).isEqualTo(4); - assertThat(sorted.get(0)).isEqualTo(firstPerson); - assertThat(sorted.get(1)).isEqualTo(secondPerson); - assertThat(sorted.get(2)).isEqualTo(thirdPerson); - assertThat(sorted.get(3)).isEqualTo(fourthPerson); - + assertThat(sorted).containsExactly(firstPerson, secondPerson, thirdPerson, fourthPerson); } From e32c6e5f38659fcf90f0c528d0fe6e238dae80a0 Mon Sep 17 00:00:00 2001 From: Thangtq211 Date: Tue, 11 Apr 2017 20:27:30 +0700 Subject: [PATCH 290/291] BAEL-635 Overview of Spring 5 (#1633) * Overview of Spring 5 * Overview of Spring 5 * BAEL-635 Formatting --- spring-5/pom.xml | 38 ++- .../jupiter/MethodParameterFactory.java | 46 +++ .../jupiter/ParameterAutowireUtils.java | 46 +++ .../com/baeldung/jupiter/SpringExtension.java | 94 ++++++ .../baeldung/jupiter/SpringJUnit5Config.java | 40 +++ .../java/com/baeldung/jupiter/TestConfig.java | 20 ++ .../java/com/baeldung/web/reactive/Task.java | 31 ++ ...nctionalWebApplicationIntegrationTest.java | 269 +++++++++--------- .../Spring5JUnit5ComposedAnnotationTests.java | 38 +++ .../jupiter/Spring5JUnit5ParallelTest.java | 29 ++ .../baeldung/jupiter/Spring5JUnit5Tests.java | 27 ++ .../jupiter/Spring5Java8NewFeaturesTest.java | 33 +++ .../Spring5ReactiveServerClientTest.java | 110 +++++++ 13 files changed, 684 insertions(+), 137 deletions(-) create mode 100644 spring-5/src/main/java/com/baeldung/jupiter/MethodParameterFactory.java create mode 100644 spring-5/src/main/java/com/baeldung/jupiter/ParameterAutowireUtils.java create mode 100644 spring-5/src/main/java/com/baeldung/jupiter/SpringExtension.java create mode 100644 spring-5/src/main/java/com/baeldung/jupiter/SpringJUnit5Config.java create mode 100644 spring-5/src/main/java/com/baeldung/jupiter/TestConfig.java create mode 100644 spring-5/src/main/java/com/baeldung/web/reactive/Task.java create mode 100644 spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ComposedAnnotationTests.java create mode 100644 spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ParallelTest.java create mode 100644 spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5Tests.java create mode 100644 spring-5/src/test/java/com/baeldung/jupiter/Spring5Java8NewFeaturesTest.java create mode 100644 spring-5/src/test/java/com/baeldung/jupiter/Spring5ReactiveServerClientTest.java diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 2c96bae9bc..ec55a878c7 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung @@ -15,7 +15,7 @@ org.springframework.boot spring-boot-starter-parent 2.0.0.BUILD-SNAPSHOT - + @@ -58,11 +58,39 @@ h2 runtime + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + + + org.springframework + spring-test + ${spring.test.version} + org.springframework.boot spring-boot-starter-test test + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.platform + junit-platform-surefire-provider + ${junit.platform.version} + test + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + @@ -92,7 +120,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.19.1 + ${maven-surefire-plugin.version} methods true @@ -143,6 +171,10 @@ UTF-8 UTF-8 1.8 + 1.0.0-M3 + 5.0.0-M3 + 4.3.7.RELEASE + 2.19.1 diff --git a/spring-5/src/main/java/com/baeldung/jupiter/MethodParameterFactory.java b/spring-5/src/main/java/com/baeldung/jupiter/MethodParameterFactory.java new file mode 100644 index 0000000000..85bd505d11 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/jupiter/MethodParameterFactory.java @@ -0,0 +1,46 @@ +package com.baeldung.jupiter; + +import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; +import org.springframework.util.Assert; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +abstract class MethodParameterFactory { + + private MethodParameterFactory() { + } + + public static MethodParameter createMethodParameter(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + if (executable instanceof Method) { + return new MethodParameter((Method) executable, getIndex(parameter)); + } + return new MethodParameter((Constructor) executable, getIndex(parameter)); + } + + public static SynthesizingMethodParameter createSynthesizingMethodParameter(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + if (executable instanceof Method) { + return new SynthesizingMethodParameter((Method) executable, getIndex(parameter)); + } + throw new UnsupportedOperationException("Cannot create a SynthesizingMethodParameter for a constructor parameter: " + parameter); + } + + private static int getIndex(Parameter parameter) { + Assert.notNull(parameter, "Parameter must not be null"); + Executable executable = parameter.getDeclaringExecutable(); + Parameter[] parameters = executable.getParameters(); + for (int i = 0; i < parameters.length; i++) { + if (parameters[i] == parameter) { + return i; + } + } + throw new IllegalStateException(String.format("Failed to resolve index of parameter [%s] in executable [%s]", parameter, executable.toGenericString())); + } +} diff --git a/spring-5/src/main/java/com/baeldung/jupiter/ParameterAutowireUtils.java b/spring-5/src/main/java/com/baeldung/jupiter/ParameterAutowireUtils.java new file mode 100644 index 0000000000..068c6af381 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/jupiter/ParameterAutowireUtils.java @@ -0,0 +1,46 @@ +package com.baeldung.jupiter; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.context.ApplicationContext; +import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.AnnotatedElementUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Optional; + +import static org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation; + +abstract class ParameterAutowireUtils { + + private ParameterAutowireUtils() { + } + + public static boolean isAutowirable(Parameter parameter) { + return ApplicationContext.class.isAssignableFrom(parameter.getType()) || hasAnnotation(parameter, Autowired.class) || hasAnnotation(parameter, Qualifier.class) || hasAnnotation(parameter, Value.class); + } + + public static Object resolveDependency(Parameter parameter, Class containingClass, ApplicationContext applicationContext) { + + boolean required = findMergedAnnotation(parameter, Autowired.class) + .map(Autowired::required) + .orElse(true); + MethodParameter methodParameter = (parameter.getDeclaringExecutable() instanceof Method ? MethodParameterFactory.createSynthesizingMethodParameter(parameter) : MethodParameterFactory.createMethodParameter(parameter)); + DependencyDescriptor descriptor = new DependencyDescriptor(methodParameter, required); + descriptor.setContainingClass(containingClass); + + return applicationContext + .getAutowireCapableBeanFactory() + .resolveDependency(descriptor, null); + } + + private static Optional findMergedAnnotation(AnnotatedElement element, Class annotationType) { + + return Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(element, annotationType)); + } +} diff --git a/spring-5/src/main/java/com/baeldung/jupiter/SpringExtension.java b/spring-5/src/main/java/com/baeldung/jupiter/SpringExtension.java new file mode 100644 index 0000000000..08fa0c4768 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/jupiter/SpringExtension.java @@ -0,0 +1,94 @@ +package com.baeldung.jupiter; + +import org.junit.jupiter.api.extension.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextManager; +import org.springframework.util.Assert; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +public class SpringExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor, BeforeEachCallback, AfterEachCallback, ParameterResolver { + + private static final ExtensionContext.Namespace namespace = ExtensionContext.Namespace.create(SpringExtension.class); + + @Override + public void beforeAll(ContainerExtensionContext context) throws Exception { + getTestContextManager(context).beforeTestClass(); + } + + @Override + public void afterAll(ContainerExtensionContext context) throws Exception { + try { + getTestContextManager(context).afterTestClass(); + } finally { + context + .getStore(namespace) + .remove(context + .getTestClass() + .get()); + } + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + getTestContextManager(context).prepareTestInstance(testInstance); + } + + @Override + public void beforeEach(TestExtensionContext context) throws Exception { + Object testInstance = context.getTestInstance(); + Method testMethod = context + .getTestMethod() + .get(); + getTestContextManager(context).beforeTestMethod(testInstance, testMethod); + } + + @Override + public void afterEach(TestExtensionContext context) throws Exception { + Object testInstance = context.getTestInstance(); + Method testMethod = context + .getTestMethod() + .get(); + Throwable testException = context + .getTestException() + .orElse(null); + getTestContextManager(context).afterTestMethod(testInstance, testMethod, testException); + } + + @Override + public boolean supports(ParameterContext parameterContext, ExtensionContext extensionContext) { + Parameter parameter = parameterContext.getParameter(); + Executable executable = parameter.getDeclaringExecutable(); + return (executable instanceof Constructor && AnnotatedElementUtils.hasAnnotation(executable, Autowired.class)) || ParameterAutowireUtils.isAutowirable(parameter); + } + + @Override + public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext) { + Parameter parameter = parameterContext.getParameter(); + Class testClass = extensionContext + .getTestClass() + .get(); + ApplicationContext applicationContext = getApplicationContext(extensionContext); + return ParameterAutowireUtils.resolveDependency(parameter, testClass, applicationContext); + } + + private ApplicationContext getApplicationContext(ExtensionContext context) { + return getTestContextManager(context) + .getTestContext() + .getApplicationContext(); + } + + private TestContextManager getTestContextManager(ExtensionContext context) { + Assert.notNull(context, "ExtensionContext must not be null"); + Class testClass = context + .getTestClass() + .get(); + ExtensionContext.Store store = context.getStore(namespace); + return store.getOrComputeIfAbsent(testClass, TestContextManager::new, TestContextManager.class); + } +} diff --git a/spring-5/src/main/java/com/baeldung/jupiter/SpringJUnit5Config.java b/spring-5/src/main/java/com/baeldung/jupiter/SpringJUnit5Config.java new file mode 100644 index 0000000000..e8b9cc500f --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/jupiter/SpringJUnit5Config.java @@ -0,0 +1,40 @@ +package com.baeldung.jupiter; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.annotation.AliasFor; +import org.springframework.test.context.ContextConfiguration; + +import java.lang.annotation.*; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SpringJUnit5Config { + + @AliasFor(annotation = ContextConfiguration.class, attribute = "classes") + Class[] value() default {}; + + @AliasFor(annotation = ContextConfiguration.class) + Class[] classes() default {}; + + @AliasFor(annotation = ContextConfiguration.class) + String[] locations() default {}; + + @AliasFor(annotation = ContextConfiguration.class) + Class>[] initializers() default {}; + + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritLocations() default true; + + @AliasFor(annotation = ContextConfiguration.class) + boolean inheritInitializers() default true; + + @AliasFor(annotation = ContextConfiguration.class) + String name() default ""; +} diff --git a/spring-5/src/main/java/com/baeldung/jupiter/TestConfig.java b/spring-5/src/main/java/com/baeldung/jupiter/TestConfig.java new file mode 100644 index 0000000000..a29f77c5df --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/jupiter/TestConfig.java @@ -0,0 +1,20 @@ +package com.baeldung.jupiter; + +import com.baeldung.web.reactive.Task; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; + +@Configuration +public class TestConfig { + + @Bean + static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } + + @Bean + Task taskName() { + return new Task("taskName", 1); + } +} diff --git a/spring-5/src/main/java/com/baeldung/web/reactive/Task.java b/spring-5/src/main/java/com/baeldung/web/reactive/Task.java new file mode 100644 index 0000000000..84193d9354 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/web/reactive/Task.java @@ -0,0 +1,31 @@ +package com.baeldung.web.reactive; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Task { + + private final String name; + + private final int id; + + public Task(@JsonProperty("name") String name, @JsonProperty("id") int id) { + this.name = name; + this.id = id; + } + + public String getName() { + return this.name; + } + + public int getId() { + return this.id; + } + + @Override + public String toString() { + return "Task{" + + "name='" + name + '\'' + + ", id=" + id + + '}'; + } +} diff --git a/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java b/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java index bf28ed1e7d..dda25f46f7 100644 --- a/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java +++ b/spring-5/src/test/java/com/baeldung/functional/FunctionalWebApplicationIntegrationTest.java @@ -7,7 +7,7 @@ import org.springframework.boot.web.server.WebServer; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; -import org.springframework.test.web.reactive.server.WebTestClient; +//import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyInserters; @@ -15,140 +15,141 @@ import org.springframework.web.reactive.function.BodyInserters; import static org.springframework.web.reactive.function.BodyInserters.fromObject; import static org.springframework.web.reactive.function.BodyInserters.fromResource; +// TODO The class does not compile, WebTestClient cannot be resolved. Missing dependency? public class FunctionalWebApplicationIntegrationTest { - private static WebTestClient client; - private static WebServer server; - - @BeforeClass - public static void setup() throws Exception { - server = new FunctionalWebApplication().start(); - client = WebTestClient - .bindToServer() - .baseUrl("http://localhost:" + server.getPort()) - .build(); - } - - @AfterClass - public static void destroy() { - server.stop(); - } - - @Test - public void givenRouter_whenGetTest_thenGotHelloWorld() throws Exception { - client - .get() - .uri("/test") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .value() - .isEqualTo("helloworld"); - } - - @Test - public void givenIndexFilter_whenRequestRoot_thenRewrittenToTest() throws Exception { - client - .get() - .uri("/") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .value() - .isEqualTo("helloworld"); - } - - @Test - public void givenLoginForm_whenPostValidToken_thenSuccess() throws Exception { - MultiValueMap formData = new LinkedMultiValueMap<>(1); - formData.add("user", "baeldung"); - formData.add("token", "you_know_what_to_do"); - - client - .post() - .uri("/login") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .exchange(BodyInserters.fromFormData(formData)) - .expectStatus() - .isOk() - .expectBody(String.class) - .value() - .isEqualTo("welcome back!"); - } - - @Test - public void givenLoginForm_whenRequestWithInvalidToken_thenFail() throws Exception { - MultiValueMap formData = new LinkedMultiValueMap<>(2); - formData.add("user", "baeldung"); - formData.add("token", "try_again"); - - client - .post() - .uri("/login") - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .exchange(BodyInserters.fromFormData(formData)) - .expectStatus() - .isBadRequest(); - } - - @Test - public void givenUploadForm_whenRequestWithMultipartData_thenSuccess() throws Exception { - Resource resource = new ClassPathResource("/baeldung-weekly.png"); - client - .post() - .uri("/upload") - .contentType(MediaType.MULTIPART_FORM_DATA) - .exchange(fromResource(resource)) - .expectStatus() - .isOk() - .expectBody(String.class) - .value() - .isEqualTo(String.valueOf(resource.contentLength())); - } - - @Test - public void givenActors_whenAddActor_thenAdded() throws Exception { - client - .get() - .uri("/actor") - .exchange() - .expectStatus() - .isOk() - .expectBody(Actor.class) - .list() - .hasSize(2); - - client - .post() - .uri("/actor") - .exchange(fromObject(new Actor("Clint", "Eastwood"))) - .expectStatus() - .isOk(); - - client - .get() - .uri("/actor") - .exchange() - .expectStatus() - .isOk() - .expectBody(Actor.class) - .list() - .hasSize(3); - } - - @Test - public void givenResources_whenAccess_thenGot() throws Exception { - client - .get() - .uri("/files/hello.txt") - .exchange() - .expectStatus() - .isOk() - .expectBody(String.class) - .value() - .isEqualTo("hello"); - } +// private static WebTestClient client; +// private static WebServer server; +// +// @BeforeClass +// public static void setup() throws Exception { +// server = new FunctionalWebApplication().start(); +// client = WebTestClient +// .bindToServer() +// .baseUrl("http://localhost:" + server.getPort()) +// .build(); +// } +// +// @AfterClass +// public static void destroy() { +// server.stop(); +// } +// +// @Test +// public void givenRouter_whenGetTest_thenGotHelloWorld() throws Exception { +// client +// .get() +// .uri("/test") +// .exchange() +// .expectStatus() +// .isOk() +// .expectBody(String.class) +// .value() +// .isEqualTo("helloworld"); +// } +// +// @Test +// public void givenIndexFilter_whenRequestRoot_thenRewrittenToTest() throws Exception { +// client +// .get() +// .uri("/") +// .exchange() +// .expectStatus() +// .isOk() +// .expectBody(String.class) +// .value() +// .isEqualTo("helloworld"); +// } +// +// @Test +// public void givenLoginForm_whenPostValidToken_thenSuccess() throws Exception { +// MultiValueMap formData = new LinkedMultiValueMap<>(1); +// formData.add("user", "baeldung"); +// formData.add("token", "you_know_what_to_do"); +// +// client +// .post() +// .uri("/login") +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .exchange(BodyInserters.fromFormData(formData)) +// .expectStatus() +// .isOk() +// .expectBody(String.class) +// .value() +// .isEqualTo("welcome back!"); +// } +// +// @Test +// public void givenLoginForm_whenRequestWithInvalidToken_thenFail() throws Exception { +// MultiValueMap formData = new LinkedMultiValueMap<>(2); +// formData.add("user", "baeldung"); +// formData.add("token", "try_again"); +// +// client +// .post() +// .uri("/login") +// .contentType(MediaType.APPLICATION_FORM_URLENCODED) +// .exchange(BodyInserters.fromFormData(formData)) +// .expectStatus() +// .isBadRequest(); +// } +// +// @Test +// public void givenUploadForm_whenRequestWithMultipartData_thenSuccess() throws Exception { +// Resource resource = new ClassPathResource("/baeldung-weekly.png"); +// client +// .post() +// .uri("/upload") +// .contentType(MediaType.MULTIPART_FORM_DATA) +// .exchange(fromResource(resource)) +// .expectStatus() +// .isOk() +// .expectBody(String.class) +// .value() +// .isEqualTo(String.valueOf(resource.contentLength())); +// } +// +// @Test +// public void givenActors_whenAddActor_thenAdded() throws Exception { +// client +// .get() +// .uri("/actor") +// .exchange() +// .expectStatus() +// .isOk() +// .expectBody(Actor.class) +// .list() +// .hasSize(2); +// +// client +// .post() +// .uri("/actor") +// .exchange(fromObject(new Actor("Clint", "Eastwood"))) +// .expectStatus() +// .isOk(); +// +// client +// .get() +// .uri("/actor") +// .exchange() +// .expectStatus() +// .isOk() +// .expectBody(Actor.class) +// .list() +// .hasSize(3); +// } +// +// @Test +// public void givenResources_whenAccess_thenGot() throws Exception { +// client +// .get() +// .uri("/files/hello.txt") +// .exchange() +// .expectStatus() +// .isOk() +// .expectBody(String.class) +// .value() +// .isEqualTo("hello"); +// } } diff --git a/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ComposedAnnotationTests.java b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ComposedAnnotationTests.java new file mode 100644 index 0000000000..d15857e0a5 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ComposedAnnotationTests.java @@ -0,0 +1,38 @@ +package com.baeldung.jupiter; + +import com.baeldung.web.reactive.Task; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringJUnit5Config(TestConfig.class) +@DisplayName("@SpringJUnit5Config Tests") +class Spring5JUnit5ComposedAnnotationTests { + + @Autowired + Task task; + + @Autowired + List tasks; + + @Test + @DisplayName("ApplicationContext injected into method") + void givenAMethodName_whenInjecting_thenApplicationContextInjectedIntoMethod(ApplicationContext applicationContext) { + assertNotNull(applicationContext, "ApplicationContext should have been injected into method by Spring"); + assertEquals(this.task, applicationContext.getBean("taskName", Task.class)); + } + + @Test + @DisplayName("Spring @Beans injected into fields") + void givenAnObject_whenInjecting_thenSpringBeansInjected() { + assertNotNull(task, "Task should have been @Autowired by Spring"); + assertEquals("taskName", task.getName(), "Task's name"); + assertEquals(1, tasks.size(), "Number of Tasks in context"); + } +} diff --git a/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ParallelTest.java b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ParallelTest.java new file mode 100644 index 0000000000..a060b78c93 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5ParallelTest.java @@ -0,0 +1,29 @@ +package com.baeldung.jupiter; + +import com.baeldung.IntegrationTestExample1; +import com.baeldung.IntegrationTestExample2; +import org.junit.experimental.ParallelComputer; +import org.junit.jupiter.api.Test; +import org.junit.runner.Computer; +import org.junit.runner.JUnitCore; + +public class Spring5JUnit5ParallelTest { + + @Test + public void givenTwoTestClasses_whenJUnitRunParallel_thenTheTestsExecutingParallel() { + final Class[] classes = { + IntegrationTestExample1.class, IntegrationTestExample2.class + }; + + JUnitCore.runClasses(new ParallelComputer(true, true), classes); + } + + @Test + public void givenTwoTestClasses_whenJUnitRunParallel_thenTheTestsExecutingLinear() { + final Class[] classes = { + IntegrationTestExample1.class, IntegrationTestExample2.class + }; + + JUnitCore.runClasses(new Computer(), classes); + } +} \ No newline at end of file diff --git a/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5Tests.java b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5Tests.java new file mode 100644 index 0000000000..c4c3148b1e --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/jupiter/Spring5JUnit5Tests.java @@ -0,0 +1,27 @@ +package com.baeldung.jupiter; + +import com.baeldung.web.reactive.Task; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestConfig.class) +class Spring5JUnit5Tests { + + @Autowired + Task task; + + @Test + void givenAMethodName_whenInjecting_thenApplicationContextInjectedIntoMetho(ApplicationContext applicationContext) { + assertNotNull(applicationContext, "ApplicationContext should have been injected by Spring"); + assertEquals(this.task, applicationContext.getBean("taskName", Task.class)); + } +} diff --git a/spring-5/src/test/java/com/baeldung/jupiter/Spring5Java8NewFeaturesTest.java b/spring-5/src/test/java/com/baeldung/jupiter/Spring5Java8NewFeaturesTest.java new file mode 100644 index 0000000000..36adf1f7ff --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/jupiter/Spring5Java8NewFeaturesTest.java @@ -0,0 +1,33 @@ +package com.baeldung.jupiter; + +import org.junit.jupiter.api.Test; +import java.util.function.Supplier; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class Spring5Java8NewFeaturesTest { + + @FunctionalInterface + public interface FunctionalInterfaceExample { + Result reverseString(Input input); + } + + public class StringUtils{ + public FunctionalInterfaceExample + functionLambdaString = s -> { + return Pattern.compile(" +").splitAsStream(s) + .map(word->new StringBuilder(word).reverse()) + .collect(Collectors.joining(" ")); + }; + } + + @Test + void givenStringUtil_whenSupplierCall_thenFunctionalInterfaceReverseString() + throws Exception { + Supplier stringUtilsSupplier = StringUtils::new; + + assertEquals(stringUtilsSupplier.get().functionLambdaString + .reverseString("hello"), "olleh"); + } +} diff --git a/spring-5/src/test/java/com/baeldung/jupiter/Spring5ReactiveServerClientTest.java b/spring-5/src/test/java/com/baeldung/jupiter/Spring5ReactiveServerClientTest.java new file mode 100644 index 0000000000..2252c255ee --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/jupiter/Spring5ReactiveServerClientTest.java @@ -0,0 +1,110 @@ +package com.baeldung.jupiter; + +import com.baeldung.web.reactive.Task; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.ExchangeFunctions; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.ipc.netty.NettyContext; +import reactor.ipc.netty.http.server.HttpServer; + +import java.net.URI; +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RequestPredicates.POST; + +public class Spring5ReactiveServerClientTest { + + private static NettyContext nettyContext; + + @BeforeAll + public static void setUp() throws Exception { + HttpServer server = HttpServer.create("localhost", 8080); + RouterFunction route = RouterFunctions + .route(POST("/task/process"), request -> ServerResponse + .ok() + .body(request + .bodyToFlux(Task.class) + .map(ll -> new Task("TaskName", 1)), Task.class)) + .and(RouterFunctions.route(GET("/task"), request -> ServerResponse + .ok() + .body(Mono.just("server is alive"), String.class))); + HttpHandler httpHandler = RouterFunctions.toHttpHandler(route); + ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); + nettyContext = server + .newHandler(adapter) + .block(); + } + + @AfterAll + public static void shutDown() { + nettyContext.dispose(); + } + + @Test + public void givenCheckTask_whenServerHandle_thenServerResponseALiveString() throws Exception { + WebClient client = WebClient.create("http://localhost:8080"); + Mono result = client + .get() + .uri("/task") + .exchange() + .then(response -> response.bodyToMono(String.class)); + + assertThat(result.block()).isInstanceOf(String.class); + } + + @Test + public void givenThreeTasks_whenServerHandleTheTasks_thenServerResponseATask() throws Exception { + URI uri = URI.create("http://localhost:8080/task/process"); + ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector()); + ClientRequest request = ClientRequest + .method(HttpMethod.POST, uri) + .body(BodyInserters.fromPublisher(getLatLngs(), Task.class)) + .build(); + + Flux taskResponse = exchange + .exchange(request) + .flatMap(response -> response.bodyToFlux(Task.class)); + + assertThat(taskResponse.blockFirst()).isInstanceOf(Task.class); + } + + @Test + public void givenCheckTask_whenServerHandle_thenOragicServerResponseALiveString() throws Exception { + URI uri = URI.create("http://localhost:8080/task"); + ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector()); + ClientRequest request = ClientRequest + .method(HttpMethod.GET, uri) + .body(BodyInserters.fromPublisher(getLatLngs(), Task.class)) + .build(); + + Flux taskResponse = exchange + .exchange(request) + .flatMap(response -> response.bodyToFlux(String.class)); + + assertThat(taskResponse.blockFirst()).isInstanceOf(String.class); + } + + private static Flux getLatLngs() { + return Flux + .range(0, 3) + .zipWith(Flux.interval(Duration.ofSeconds(1))) + .map(x -> new Task("taskname", 1)) + .doOnNext(ll -> System.out.println("Produced: {}" + ll)); + } +} From d21d7a1e2ec80eba0aed5011e10f3e5f03dfa52f Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Tue, 11 Apr 2017 21:11:58 -0500 Subject: [PATCH 291/291] BAEL-567: updated README (#1640) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README * BAEL-415: Custom Scope * BAEL-415: Custom Scope - renamed classes to reflect TenantScope * README file updates for BAEL-723, BAEL-763, and BAEL-415 * BAEL-735: README * BAEL-567: README --- algorithms/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/README.md b/algorithms/README.md index a0e10246e0..00e0646f47 100644 --- a/algorithms/README.md +++ b/algorithms/README.md @@ -4,3 +4,4 @@ - [Introduction to Cobertura](http://www.baeldung.com/cobertura) - [Ant Colony Optimization](http://www.baeldung.com/java-ant-colony-optimization) - [Validating Input With Finite Automata in Java](http://www.baeldung.com/finite-automata-java) +- [Introduction to Jenetics Library](http://www.baeldung.com/jenetics)