From 334dd3e934ba9f3b4b364f4f945864b0901b6bc1 Mon Sep 17 00:00:00 2001 From: Fabian Kreis Date: Wed, 24 Jun 2015 15:13:42 +0200 Subject: [PATCH 01/18] updated gitignore -> ignore jsclient --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1815ac8d9..84b6473e9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ eclipse-target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +oasp4j-samples/oasp4j-sample-server/src/main/webapp/jsclient/ From 731580fc2f26906024edf02db940294403122dae Mon Sep 17 00:00:00 2001 From: Fabian Kreis Date: Thu, 25 Jun 2015 11:35:28 +0200 Subject: [PATCH 02/18] created specialEntity --- .../dataaccess/api/SpecialEntity.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java new file mode 100644 index 000000000..112ba45c2 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -0,0 +1,129 @@ +package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Special; + +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * The {@link io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity persistent entity} for + * {@link Special}. + * + * @author fkreis + */ +@Entity(name = "Special") +@Table() +public class SpecialEntity extends MenuItemEntity { + + private static final long serialVersionUID = 1L; + + private OfferEntity offer; + + private int startingWeekDay; + + private int startingHour; + + private int endgingWeekDay; + + /** + * @return offer + */ + public OfferEntity getOffer() { + + return this.offer; + } + + /** + * @param offer new value of {@link #getOffer}. + */ + public void setOffer(OfferEntity offer) { + + this.offer = offer; + } + + /** + * @return startingWeekDay + */ + public int getStartingWeekDay() { + + return this.startingWeekDay; + } + + /** + * @param startingWeekDay new value of {@link #getStartingWeekDay}. + */ + public void setStartingWeekDay(int startingWeekDay) { + + this.startingWeekDay = startingWeekDay; + } + + /** + * @return startingHour + */ + public int getStartingHour() { + + return this.startingHour; + } + + /** + * @param startingHour new value of {@link #getStartingHour}. + */ + public void setStartingHour(int startingHour) { + + this.startingHour = startingHour; + } + + /** + * @return endgingWeekDay + */ + public int getEndgingWeekDay() { + + return this.endgingWeekDay; + } + + /** + * @param endgingWeekDay new value of {@link #getEndgingWeekDay}. + */ + public void setEndgingWeekDay(int endgingWeekDay) { + + this.endgingWeekDay = endgingWeekDay; + } + + /** + * @return endingHour + */ + public int getEndingHour() { + + return this.endingHour; + } + + /** + * @param endingHour new value of {@link #getEndingHour}. + */ + public void setEndingHour(int endingHour) { + + this.endingHour = endingHour; + } + + /** + * @return specialPrice + */ + public Money getSpecialPrice() { + + return this.specialPrice; + } + + /** + * @param specialPrice new value of {@link #getSpecialPrice}. + */ + public void setSpecialPrice(Money specialPrice) { + + this.specialPrice = specialPrice; + } + + private int endingHour; + + private Money specialPrice; + +} \ No newline at end of file From 7113b538474dc9c92bb7a7e74babcf2a988a0def Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Thu, 25 Jun 2015 15:30:21 +0200 Subject: [PATCH 03/18] TP use case data model clean up --- .../dataaccess/api/SpecialEntity.java | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index 112ba45c2..f56bc5f86 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -1,10 +1,6 @@ package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.Special; - -import javax.persistence.Entity; -import javax.persistence.Table; /** * The {@link io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity persistent entity} for @@ -12,11 +8,7 @@ * * @author fkreis */ -@Entity(name = "Special") -@Table() -public class SpecialEntity extends MenuItemEntity { - - private static final long serialVersionUID = 1L; +public class SpecialEntity { private OfferEntity offer; @@ -24,7 +16,11 @@ public class SpecialEntity extends MenuItemEntity { private int startingHour; - private int endgingWeekDay; + private int endingWeekDay; + + private int endingHour; + + private Money specialPrice; /** * @return offer @@ -75,19 +71,19 @@ public void setStartingHour(int startingHour) { } /** - * @return endgingWeekDay + * @return endingWeekDay */ - public int getEndgingWeekDay() { + public int getEndingWeekDay() { - return this.endgingWeekDay; + return this.endingWeekDay; } /** - * @param endgingWeekDay new value of {@link #getEndgingWeekDay}. + * @param endingWeekDay new value of {@link #getEndingWeekDay}. */ - public void setEndgingWeekDay(int endgingWeekDay) { + public void setEndingWeekDay(int endingWeekDay) { - this.endgingWeekDay = endgingWeekDay; + this.endingWeekDay = endingWeekDay; } /** @@ -122,8 +118,4 @@ public void setSpecialPrice(Money specialPrice) { this.specialPrice = specialPrice; } - private int endingHour; - - private Money specialPrice; - -} \ No newline at end of file +} From d76b991a1198622497092f783470a1b5f3d92089 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Thu, 25 Jun 2015 16:06:44 +0200 Subject: [PATCH 04/18] Further development of TP data model --- .../common/api/datatype/DayOfWeek.java | 32 +++++++ .../dataaccess/api/SpecialEntity.java | 74 ++------------- .../dataaccess/api/WeeklySchedulePeriod.java | 92 +++++++++++++++++++ 3 files changed, 134 insertions(+), 64 deletions(-) create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java new file mode 100644 index 000000000..66a650b69 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java @@ -0,0 +1,32 @@ +package io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype; + +import java.util.Calendar; + +/** + * Day of Week enum. + * + * @author mbrunnli + */ +public enum DayOfWeek { + + MONDAY(Calendar.MONDAY), TUESDAY(Calendar.TUESDAY), WEDNESDAY(Calendar.WEDNESDAY), THURSDAY(Calendar.THURSDAY), FRIDAY( + Calendar.FRIDAY), SATURDAY(Calendar.SATURDAY), SUNDAY(Calendar.SUNDAY); + + /** {@link Calendar#DAY_OF_WEEK} representation */ + private int calendarRepresentation; + + private DayOfWeek(int calendarRepresentation) { + + this.calendarRepresentation = calendarRepresentation; + } + + /** + * Returns the {@link Calendar#DAY_OF_WEEK} representation. + * + * @return {@link Calendar#DAY_OF_WEEK} representation + */ + public int toCalendarDayOfWeek() { + + return this.calendarRepresentation; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index f56bc5f86..f540873a9 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -1,24 +1,18 @@ package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; /** - * The {@link io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity persistent entity} for - * {@link Special}. + * The {@link ApplicationPersistenceEntity persistent entity} for a special. * - * @author fkreis + * @author mbrunnli */ public class SpecialEntity { private OfferEntity offer; - private int startingWeekDay; - - private int startingHour; - - private int endingWeekDay; - - private int endingHour; + private WeeklySchedulePeriod activePeriod; private Money specialPrice; @@ -39,67 +33,19 @@ public void setOffer(OfferEntity offer) { } /** - * @return startingWeekDay - */ - public int getStartingWeekDay() { - - return this.startingWeekDay; - } - - /** - * @param startingWeekDay new value of {@link #getStartingWeekDay}. - */ - public void setStartingWeekDay(int startingWeekDay) { - - this.startingWeekDay = startingWeekDay; - } - - /** - * @return startingHour - */ - public int getStartingHour() { - - return this.startingHour; - } - - /** - * @param startingHour new value of {@link #getStartingHour}. - */ - public void setStartingHour(int startingHour) { - - this.startingHour = startingHour; - } - - /** - * @return endingWeekDay - */ - public int getEndingWeekDay() { - - return this.endingWeekDay; - } - - /** - * @param endingWeekDay new value of {@link #getEndingWeekDay}. - */ - public void setEndingWeekDay(int endingWeekDay) { - - this.endingWeekDay = endingWeekDay; - } - - /** - * @return endingHour + * @return activePeriod */ - public int getEndingHour() { + public WeeklySchedulePeriod getActivePeriod() { - return this.endingHour; + return this.activePeriod; } /** - * @param endingHour new value of {@link #getEndingHour}. + * @param activePeriod new value of {@link #getActivePeriod}. */ - public void setEndingHour(int endingHour) { + public void setActivePeriod(WeeklySchedulePeriod activePeriod) { - this.endingHour = endingHour; + this.activePeriod = activePeriod; } /** diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java new file mode 100644 index 000000000..35798a4f8 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java @@ -0,0 +1,92 @@ +package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.DayOfWeek; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +/** + * Weekly period describing a starting and an ending point. Each is defined as a fixed hour (24h-format) at a specific + * day of week. + * + * @author mbrunnli + */ +public class WeeklySchedulePeriod { + + private DayOfWeek startingDay; + + private int startingHour; + + private DayOfWeek endingDay; + + private int endingHour; + + /** + * @return startingDay + */ + public DayOfWeek getStartingDay() { + + return this.startingDay; + } + + /** + * @param startingDay new value of {@link #getStartingDay}. + */ + public void setStartingDay(DayOfWeek startingDay) { + + this.startingDay = startingDay; + } + + /** + * @return startingHour + */ + @Max(24) + @Min(0) + public int getStartingHour() { + + return this.startingHour; + } + + /** + * @param startingHour new value of {@link #getStartingHour}. + */ + public void setStartingHour(int startingHour) { + + this.startingHour = startingHour; + } + + /** + * @return endingDay + */ + public DayOfWeek getEndingDay() { + + return this.endingDay; + } + + /** + * @param endingDay new value of {@link #getEndingDay}. + */ + public void setEndingDay(DayOfWeek endingDay) { + + this.endingDay = endingDay; + } + + /** + * @return endingHour + */ + @Max(24) + @Min(0) + public int getEndingHour() { + + return this.endingHour; + } + + /** + * @param endingHour new value of {@link #getEndingHour}. + */ + public void setEndingHour(int endingHour) { + + this.endingHour = endingHour; + } + +} From 0a8b701d294aa5d10f00eb808e8e08dd26d071fa Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Thu, 25 Jun 2015 16:09:00 +0200 Subject: [PATCH 05/18] Further development of TP data model --- .../offermanagement/dataaccess/api/SpecialEntity.java | 6 +++--- .../{WeeklySchedulePeriod.java => WeeklyPeriodEntity.java} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/{WeeklySchedulePeriod.java => WeeklyPeriodEntity.java} (97%) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index f540873a9..591395bc6 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -12,7 +12,7 @@ public class SpecialEntity { private OfferEntity offer; - private WeeklySchedulePeriod activePeriod; + private WeeklyPeriodEntity activePeriod; private Money specialPrice; @@ -35,7 +35,7 @@ public void setOffer(OfferEntity offer) { /** * @return activePeriod */ - public WeeklySchedulePeriod getActivePeriod() { + public WeeklyPeriodEntity getActivePeriod() { return this.activePeriod; } @@ -43,7 +43,7 @@ public WeeklySchedulePeriod getActivePeriod() { /** * @param activePeriod new value of {@link #getActivePeriod}. */ - public void setActivePeriod(WeeklySchedulePeriod activePeriod) { + public void setActivePeriod(WeeklyPeriodEntity activePeriod) { this.activePeriod = activePeriod; } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java similarity index 97% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java rename to oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java index 35798a4f8..6297d8bf1 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklySchedulePeriod.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java @@ -11,7 +11,7 @@ * * @author mbrunnli */ -public class WeeklySchedulePeriod { +public class WeeklyPeriodEntity { private DayOfWeek startingDay; From 4f99a7b7a9c5a536f2830036ab691bb4fd023ce3 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Fri, 26 Jun 2015 13:18:45 +0200 Subject: [PATCH 06/18] Added JavaDoc to the TP data model --- .../dataaccess/api/SpecialEntity.java | 25 +++++++++++---- .../dataaccess/api/WeeklyPeriodEntity.java | 32 ++++++++++++++----- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index 591395bc6..393b08b0a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -2,6 +2,7 @@ import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; /** * The {@link ApplicationPersistenceEntity persistent entity} for a special. @@ -17,7 +18,9 @@ public class SpecialEntity { private Money specialPrice; /** - * @return offer + * Returns the {@link Offer} this special applies for. + * + * @return offer {@link Offer} this special applies for. */ public OfferEntity getOffer() { @@ -25,7 +28,9 @@ public OfferEntity getOffer() { } /** - * @param offer new value of {@link #getOffer}. + * Sets the {@link Offer} this special applies for. + * + * @param offer the {@link Offer} this special applies for. */ public void setOffer(OfferEntity offer) { @@ -33,7 +38,9 @@ public void setOffer(OfferEntity offer) { } /** - * @return activePeriod + * Returns the {@link WeeklyPeriodEntity active period} this special applies for. + * + * @return activePeriod the {@link WeeklyPeriodEntity active period} this special applies for. */ public WeeklyPeriodEntity getActivePeriod() { @@ -41,7 +48,9 @@ public WeeklyPeriodEntity getActivePeriod() { } /** - * @param activePeriod new value of {@link #getActivePeriod}. + * Sets the {@link WeeklyPeriodEntity active period} this special applies for. + * + * @param activePeriod the {@link WeeklyPeriodEntity active period} this special applies for. */ public void setActivePeriod(WeeklyPeriodEntity activePeriod) { @@ -49,7 +58,9 @@ public void setActivePeriod(WeeklyPeriodEntity activePeriod) { } /** - * @return specialPrice + * Returns the new {@link Money special price} for the {@link Offer}. + * + * @return specialPrice the new {@link Money special price} for the {@link Offer}. */ public Money getSpecialPrice() { @@ -57,7 +68,9 @@ public Money getSpecialPrice() { } /** - * @param specialPrice new value of {@link #getSpecialPrice}. + * Sets the new {@link Money special price} for the {@link Offer}. + * + * @param specialPrice the new {@link Money special price} for the {@link Offer}. */ public void setSpecialPrice(Money specialPrice) { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java index 6297d8bf1..d8d0720ae 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java @@ -22,7 +22,9 @@ public class WeeklyPeriodEntity { private int endingHour; /** - * @return startingDay + * Returns the {@link DayOfWeek} the period starts. + * + * @return startingDay the {@link DayOfWeek} the period starts. */ public DayOfWeek getStartingDay() { @@ -30,7 +32,9 @@ public DayOfWeek getStartingDay() { } /** - * @param startingDay new value of {@link #getStartingDay}. + * Sets the {@link DayOfWeek} the period starts. + * + * @param startingDay the {@link DayOfWeek} the period starts. */ public void setStartingDay(DayOfWeek startingDay) { @@ -38,7 +42,9 @@ public void setStartingDay(DayOfWeek startingDay) { } /** - * @return startingHour + * Returns the hour (in 24h-format) the period starts. + * + * @return startingHour the hour (in 24h-format) the period starts. */ @Max(24) @Min(0) @@ -48,7 +54,9 @@ public int getStartingHour() { } /** - * @param startingHour new value of {@link #getStartingHour}. + * Sets the hour (in 24h-format) the period starts. + * + * @param startingHour the hour (in 24h-format) the period starts. */ public void setStartingHour(int startingHour) { @@ -56,7 +64,9 @@ public void setStartingHour(int startingHour) { } /** - * @return endingDay + * Returns the {@link DayOfWeek} the period ends. + * + * @return endingDay the {@link DayOfWeek} the period ends. */ public DayOfWeek getEndingDay() { @@ -64,7 +74,9 @@ public DayOfWeek getEndingDay() { } /** - * @param endingDay new value of {@link #getEndingDay}. + * Sets the {@link DayOfWeek} the period ends. + * + * @param endingDay the {@link DayOfWeek} the period ends. */ public void setEndingDay(DayOfWeek endingDay) { @@ -72,7 +84,9 @@ public void setEndingDay(DayOfWeek endingDay) { } /** - * @return endingHour + * Returns the hour (in 24h-format) the period ends. + * + * @return endingHour the hour (in 24h-format) the period ends. */ @Max(24) @Min(0) @@ -82,7 +96,9 @@ public int getEndingHour() { } /** - * @param endingHour new value of {@link #getEndingHour}. + * Returns the hour (in 24h-format) the period ends. + * + * @param endingHour the hour (in 24h-format) the period ends. */ public void setEndingHour(int endingHour) { From 5fed3dc6922e9936eff7c43549ad57da33f74a3a Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Fri, 26 Jun 2015 13:32:48 +0200 Subject: [PATCH 07/18] adaptions of data model --- .../dataaccess/api/SpecialEntity.java | 12 ++++++++++-- .../dataaccess/api/WeeklyPeriodEntity.java | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index 393b08b0a..05f7fae70 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -4,11 +4,19 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.hibernate.envers.Audited; + /** * The {@link ApplicationPersistenceEntity persistent entity} for a special. * * @author mbrunnli */ +@Entity(name = "Special") +@Table(name = "Special") +@Audited public class SpecialEntity { private OfferEntity offer; @@ -59,7 +67,7 @@ public void setActivePeriod(WeeklyPeriodEntity activePeriod) { /** * Returns the new {@link Money special price} for the {@link Offer}. - * + * * @return specialPrice the new {@link Money special price} for the {@link Offer}. */ public Money getSpecialPrice() { @@ -69,7 +77,7 @@ public Money getSpecialPrice() { /** * Sets the new {@link Money special price} for the {@link Offer}. - * + * * @param specialPrice the new {@link Money special price} for the {@link Offer}. */ public void setSpecialPrice(Money specialPrice) { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java index d8d0720ae..0428b9b1b 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java @@ -2,15 +2,22 @@ import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.DayOfWeek; +import javax.persistence.Entity; +import javax.persistence.Table; import javax.validation.constraints.Max; import javax.validation.constraints.Min; +import org.hibernate.envers.Audited; + /** * Weekly period describing a starting and an ending point. Each is defined as a fixed hour (24h-format) at a specific * day of week. * * @author mbrunnli */ +@Entity(name = "WeeklyPeriod") +@Table(name = "WeeklyPeriod") +@Audited public class WeeklyPeriodEntity { private DayOfWeek startingDay; From a9f4f2b1687e03acd4081cca9a9c9f1599b3c1a5 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Sat, 27 Jun 2015 15:05:28 +0200 Subject: [PATCH 08/18] rename Offermanagement to be able to generate services --- .../logic/api/Offermanagement.java | 2 +- .../rest/OffermanagementRestServiceImpl.java | 54 +++++++------- .../restaurant/test/config/RestUrls.java | 2 +- ...va => OffermanagementRestServiceTest.java} | 70 +++++++++---------- 4 files changed, 64 insertions(+), 64 deletions(-) rename oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/{OfferManagementRestServiceTest.java => OffermanagementRestServiceTest.java} (81%) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java index 2b3fcea97..44225ed02 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java @@ -21,7 +21,7 @@ import javax.validation.Valid; /** - * Interface for OfferManagement. + * Interface for Offermanagement. * * @author loverbec */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java index 57adb26df..28d201c1d 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java @@ -56,15 +56,15 @@ @Transactional public class OffermanagementRestServiceImpl { - private Offermanagement offerManagement; + private Offermanagement offermanagement; /** * @param offerManagement the offerManagement to be set */ @Inject - public void setOfferManagement(Offermanagement offerManagement) { + public void setOffermanagement(Offermanagement offerManagement) { - this.offerManagement = offerManagement; + this.offermanagement = offerManagement; } /** @@ -77,7 +77,7 @@ public void setOfferManagement(Offermanagement offerManagement) { @Path("/offer/{id}") public OfferEto getOffer(@PathParam("id") Long id) { - return this.offerManagement.findOffer(id); + return this.offermanagement.findOffer(id); } /** @@ -91,7 +91,7 @@ public OfferEto getOffer(@PathParam("id") Long id) { @Path("/offer/") public OfferEto saveOffer(OfferEto offer) { - return this.offerManagement.saveOffer(offer); + return this.offermanagement.saveOffer(offer); } // although id in path is redundant, this structure is intentionally chosen @@ -108,7 +108,7 @@ public OfferEto saveOffer(OfferEto offer) { @Deprecated public OfferEto updateOffer(OfferEto offer) { - return this.offerManagement.saveOffer(offer); + return this.offermanagement.saveOffer(offer); } /** @@ -121,7 +121,7 @@ public OfferEto updateOffer(OfferEto offer) { @Deprecated public List getAllOffers() { - return this.offerManagement.findAllOffers(); + return this.offermanagement.findAllOffers(); } /** @@ -134,7 +134,7 @@ public List getAllOffers() { @Deprecated public List getAllProducts() { - return this.offerManagement.findAllProducts(); + return this.offermanagement.findAllProducts(); } /** @@ -147,7 +147,7 @@ public List getAllProducts() { @Path("/product/") public ProductEto saveProduct(ProductEto product) { - return this.offerManagement.saveProduct(product); + return this.offermanagement.saveProduct(product); } /** @@ -162,7 +162,7 @@ public ProductEto saveProduct(ProductEto product) { @Deprecated public List getAllMeals() { - return this.offerManagement.findAllMeals(); + return this.offermanagement.findAllMeals(); } /** @@ -177,7 +177,7 @@ public List getAllMeals() { @Deprecated public List getAllDrinks() { - return this.offerManagement.findAllDrinks(); + return this.offermanagement.findAllDrinks(); } /** @@ -192,7 +192,7 @@ public List getAllDrinks() { @Deprecated public List getAllSideDishes() { - return this.offerManagement.findAllSideDishes(); + return this.offermanagement.findAllSideDishes(); } /** @@ -204,7 +204,7 @@ public List getAllSideDishes() { @Path("/offer/{id}") public void deleteOffer(@PathParam("id") Long id) { - this.offerManagement.deleteOffer(id); + this.offermanagement.deleteOffer(id); } /** @@ -219,9 +219,9 @@ public void deleteOffer(@PathParam("id") Long id) { public ProductEto findProductByRevision(@PathParam("id") Long id, @PathParam("revision") Long revision) { if (revision != null) { - return this.offerManagement.findProductByRevision(id, revision); + return this.offermanagement.findProductByRevision(id, revision); } else { - return this.offerManagement.findProduct(id); + return this.offermanagement.findProduct(id); } } @@ -235,7 +235,7 @@ public ProductEto findProductByRevision(@PathParam("id") Long id, @PathParam("re @Path("/product/{id}") public ProductEto findProduct(@PathParam("id") Long id) { - return this.offerManagement.findProduct(id); + return this.offermanagement.findProduct(id); } // although id in path is redundant, this structure is intentionally chosen @@ -251,7 +251,7 @@ public ProductEto findProduct(@PathParam("id") Long id) { @Deprecated public void updateProduct(ProductEto product) { - this.offerManagement.saveProduct(product); + this.offermanagement.saveProduct(product); } /** @@ -264,7 +264,7 @@ public void updateProduct(ProductEto product) { @Path("/product/{id}/inuse") public boolean isProductInUseByOffer(@PathParam("id") Long id) { - return this.offerManagement.isProductInUseByOffer(findProduct(id)); + return this.offermanagement.isProductInUseByOffer(findProduct(id)); } /** @@ -276,7 +276,7 @@ public boolean isProductInUseByOffer(@PathParam("id") Long id) { @Path("/product/{id}") public void deleteProduct(@PathParam("id") Long id) { - this.offerManagement.deleteProduct(id); + this.offermanagement.deleteProduct(id); } /** @@ -291,7 +291,7 @@ public void deleteProduct(@PathParam("id") Long id) { @Deprecated public List getFilteredOffers(OfferFilter offerFilter, @PathParam("sortBy") OfferSortBy sortBy) { - return this.offerManagement.findOffersFiltered(offerFilter, sortBy); + return this.offermanagement.findOffersFiltered(offerFilter, sortBy); } /** @@ -306,7 +306,7 @@ public List getFilteredOffers(OfferFilter offerFilter, @PathParam("sor @Deprecated public List getFilteredProducts(ProductFilter productFilter, @PathParam("sortBy") ProductSortBy sortBy) { - return this.offerManagement.findProductsFiltered(productFilter, sortBy); + return this.offermanagement.findProductsFiltered(productFilter, sortBy); } @SuppressWarnings("javadoc") @@ -319,7 +319,7 @@ public void updateProductPicture(@PathParam("id") Long productId, throws SerialException, SQLException, IOException { Blob blob = new SerialBlob(IOUtils.readBytesFromStream(picture)); - this.offerManagement.updateProductPicture(productId, blob, binaryObjectEto); + this.offermanagement.updateProductPicture(productId, blob, binaryObjectEto); } @@ -329,13 +329,13 @@ public void updateProductPicture(@PathParam("id") Long productId, @Path("/product/{id}/picture") public MultipartBody getProductPicture(@PathParam("id") long productId) throws SQLException, IOException { - Blob blob = this.offerManagement.findProductPictureBlob(productId); + Blob blob = this.offermanagement.findProductPictureBlob(productId); // REVIEW arturk88 (hohwille) we need to find another way to stream the blob without loading into heap. // https://github.com/oasp/oasp4j-sample/pull/45 byte[] data = IOUtils.readBytesFromStream(blob.getBinaryStream()); List atts = new LinkedList<>(); - atts.add(new Attachment("binaryObjectEto", MediaType.APPLICATION_JSON, this.offerManagement + atts.add(new Attachment("binaryObjectEto", MediaType.APPLICATION_JSON, this.offermanagement .findProductPicture(productId))); atts.add(new Attachment("blob", MediaType.APPLICATION_OCTET_STREAM, new ByteArrayInputStream(data))); return new MultipartBody(atts, true); @@ -347,7 +347,7 @@ public MultipartBody getProductPicture(@PathParam("id") long productId) throws S @Path("/product/{id}/picture") public void deleteProductPicture(long productId) { - this.offerManagement.deleteProductPicture(productId); + this.offermanagement.deleteProductPicture(productId); } /** @@ -360,7 +360,7 @@ public void deleteProductPicture(long productId) { @POST public PaginatedListTo findOfferEtosByPost(OfferSearchCriteriaTo searchCriteriaTo) { - return this.offerManagement.findOfferEtos(searchCriteriaTo); + return this.offermanagement.findOfferEtos(searchCriteriaTo); } /** @@ -373,7 +373,7 @@ public PaginatedListTo findOfferEtosByPost(OfferSearchCriteriaTo searc @POST public PaginatedListTo findProductEtosByPost(ProductSearchCriteriaTo searchCriteriaTo) { - return this.offerManagement.findProductEtos(searchCriteriaTo); + return this.offermanagement.findProductEtos(searchCriteriaTo); } } diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java index 0293082ac..f8fabc57d 100644 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java +++ b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java @@ -299,7 +299,7 @@ public final static String isTableReleasableUrl(Long id) { * * @author arklos */ - public static class OfferManagement { + public static class Offermanagement { /** * */ diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OfferManagementRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java similarity index 81% rename from oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OfferManagementRestServiceTest.java rename to oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java index 610c285db..1a1594c37 100644 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OfferManagementRestServiceTest.java +++ b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java @@ -29,11 +29,11 @@ import org.junit.Test; /** - * OfferManagement rest service test + * Offermanagement rest service test * * @author arklos */ -public class OfferManagementRestServiceTest extends AbstractRestServiceTest { +public class OffermanagementRestServiceTest extends AbstractRestServiceTest { /** * Test CRUD functionality of offer. @@ -43,7 +43,7 @@ public void crudOfferTest() { // get all offers List> offers = - this.waiter.getAll(RestUrls.OfferManagement.Offer.getGetAllOffersUrl(), OfferEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); // get unused offer description List offerDescriptions = new ArrayList<>(); @@ -65,10 +65,10 @@ public void crudOfferTest() { // create a new offer OfferEto createdOffer = this.chief.post(TestData.createOffer(null, myDescription, OfferState.NORMAL, mealId, sidedishId, drinkId, 0, - new Money(new BigDecimal(2.5))), RestUrls.OfferManagement.Offer.getCreateOfferUrl(), OfferEto.class); + new Money(new BigDecimal(2.5))), RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); // get the created offer ResponseData offer = - this.waiter.get(RestUrls.OfferManagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); + this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); Assert.assertNotNull(offer.getResponseObject()); Assert.assertEquals(createdOffer.getDescription(), offer.getResponseObject().getDescription()); @@ -78,17 +78,17 @@ public void crudOfferTest() { OfferState newState = OfferState.SOLDOUT; createdOffer.setState(newState); OfferEto updatedOffer = - this.chief.post(createdOffer, RestUrls.OfferManagement.Offer.getCreateOfferUrl(), OfferEto.class); + this.chief.post(createdOffer, RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); Assert.assertEquals(newState, updatedOffer.getState()); // delete created offer - Response deleteResponse = this.chief.delete(RestUrls.OfferManagement.Offer.getDeleteOfferUrl(createdOffer.getId())); + Response deleteResponse = this.chief.delete(RestUrls.Offermanagement.Offer.getDeleteOfferUrl(createdOffer.getId())); Assert.assertEquals(deleteResponse.getStatus(), 204); // check if offer is deleted ResponseData getDeletedOfferResponse = - this.waiter.get(RestUrls.OfferManagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); + this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); Assert.assertNull(getDeletedOfferResponse.getResponseObject()); } @@ -101,7 +101,7 @@ public void crudOfferTest() { public DrinkEto createDrink() { ProductEto drink = TestData.createDrink(null, "Wasser", null, false); - DrinkEto response = this.chief.post(drink, RestUrls.OfferManagement.Product.getCreateProductUrl(), DrinkEto.class); + DrinkEto response = this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); return response; } @@ -114,12 +114,12 @@ public DrinkEto createDrink() { public void getOfferTest() { Long id = DB.OFFER_1.getId(); - ResponseData offer = this.waiter.get(RestUrls.OfferManagement.Offer.getGetOfferUrl(id), OfferEto.class); + ResponseData offer = this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); // assertThat(offer.getResponse().getStatus(), is(200)); assertThat(offer.getResponseObject().getId(), is(id)); id = TestData.DB.OFFER_2.getId(); - offer = this.waiter.get(RestUrls.OfferManagement.Offer.getGetOfferUrl(id), OfferEto.class); + offer = this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); // assertThat(offer.getResponse().getStatus(), is(200)); assertThat(offer.getResponseObject().getId(), is(id)); @@ -133,8 +133,8 @@ public void getOfferTest() { public void updateOfferTest() { Long id = Additional.CHANGED_OFFER_1.getId(); - this.chief.put(RestUrls.OfferManagement.Offer.getUpdateOfferUrl(id), Additional.CHANGED_OFFER_1); - ResponseData offer = this.chief.get(RestUrls.OfferManagement.Offer.getGetOfferUrl(id), OfferEto.class); + this.chief.put(RestUrls.Offermanagement.Offer.getUpdateOfferUrl(id), Additional.CHANGED_OFFER_1); + ResponseData offer = this.chief.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); assertThat(offer.getResponse().getStatus(), is(200)); assertThat(offer.getResponseObject().getName(), is(Additional.CHANGED_OFFER_1.getName())); } @@ -146,7 +146,7 @@ public void updateOfferTest() { public void getAllOffersTest() { List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Offer.getGetAllOffersUrl(), OfferEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); // assertThat(offer.size(), is(TestData.DB.ALL_OFFERS.size())); for (ResponseData responseData : offer) { assertThat(responseData.getResponse().getStatus(), is(200)); @@ -160,9 +160,9 @@ public void getAllOffersTest() { @Ignore public void createProduct() { - this.chief.post(RestUrls.OfferManagement.Product.getCreateProductUrl(), TestData.Additional.MEAL); + this.chief.post(RestUrls.Offermanagement.Product.getCreateProductUrl(), TestData.Additional.MEAL); List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getGetAllProductsUrl(), ProductEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllProductsUrl(), ProductEto.class); assertThat(offer.size(), is(DB.ALL_PRODUCTS.size() + 1)); } @@ -173,7 +173,7 @@ public void createProduct() { public void getAllProductsTest() { List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getGetAllProductsUrl(), ProductEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllProductsUrl(), ProductEto.class); // assertThat(offer.size(), is(DB.ALL_PRODUCTS.size())); for (ResponseData responseData : offer) { assertThat(responseData.getResponse().getStatus(), is(200)); @@ -188,7 +188,7 @@ public void getAllProductsTest() { public void getAllMealsTest() { List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getGetAllMealsUrl(), MealEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllMealsUrl(), MealEto.class); // assertThat(offer.size(), is(DB.ALL_MEALS.size())); for (ResponseData responseData : offer) { assertThat(responseData.getResponse().getStatus(), is(200)); @@ -202,7 +202,7 @@ public void getAllMealsTest() { public void getAllDrinksTest() { List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getGetAllDrinksUrl(), DrinkEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllDrinksUrl(), DrinkEto.class); // assertThat(offer.size(), is(DB.ALL_DRINKS.size())); for (ResponseData responseData : offer) { assertThat(responseData.getResponse().getStatus(), is(200)); @@ -216,7 +216,7 @@ public void getAllDrinksTest() { public void getAllSideDishesTest() { List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getGetAllSideDishesUrl(), SideDishEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllSideDishesUrl(), SideDishEto.class); // assertThat(offer.size(), is(DB.ALL_SIDE_DISHES.size())); for (ResponseData responseData : offer) { assertThat(responseData.getResponse().getStatus(), is(200)); @@ -231,10 +231,10 @@ public void getAllSideDishesTest() { public void deleteOfferTest() { List> offers = - this.chief.getAll(RestUrls.OfferManagement.Offer.getGetAllOffersUrl(), OfferEto.class); + this.chief.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); - this.chief.delete(RestUrls.OfferManagement.Offer.getDeleteOfferUrl(DB.OFFER_1.getId())); - offers = this.chief.getAll(RestUrls.OfferManagement.Offer.getGetAllOffersUrl(), OfferEto.class); + this.chief.delete(RestUrls.Offermanagement.Offer.getDeleteOfferUrl(DB.OFFER_1.getId())); + offers = this.chief.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); assertThat(offers.size(), is(DB.ALL_OFFERS.size() - 1)); } @@ -246,11 +246,11 @@ public void findProductTest() { Long drinkId = createDrink().getId(); ResponseData offer = - this.waiter.get(RestUrls.OfferManagement.Product.getFindProductUrl(drinkId), ProductEto.class); + this.waiter.get(RestUrls.Offermanagement.Product.getFindProductUrl(drinkId), ProductEto.class); assertThat(offer.getResponse().getStatus(), is(200)); assertThat(offer.getResponseObject().getId(), is(drinkId)); - offer = this.waiter.get(RestUrls.OfferManagement.Product.getFindProductUrl(drinkId + 1), ProductEto.class); + offer = this.waiter.get(RestUrls.Offermanagement.Product.getFindProductUrl(drinkId + 1), ProductEto.class); Assert.assertNull(offer.getResponseObject()); } @@ -264,14 +264,14 @@ public void findProductByRevisionTest() { // create drink ProductEto drink = TestData.createDrink(null, "Wasser", null, false); DrinkEto createdDrink = - this.chief.post(drink, RestUrls.OfferManagement.Product.getCreateProductUrl(), DrinkEto.class); + this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); // change drink createdDrink.setDescription("changed description"); - this.chief.post(createdDrink, RestUrls.OfferManagement.Product.getCreateProductUrl(), DrinkEto.class); + this.chief.post(createdDrink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); Long revision = 1L; ResponseData revisionedProductResponse = - this.waiter.get(RestUrls.OfferManagement.Product.getFindProductByRevisionUrl(createdDrink.getId(), revision), + this.waiter.get(RestUrls.Offermanagement.Product.getFindProductByRevisionUrl(createdDrink.getId(), revision), DrinkEto.class); DrinkEto revisionedProduct = revisionedProductResponse.getResponseObject(); Assert.assertEquals(revision.longValue(), revisionedProduct.getRevision().longValue()); @@ -286,11 +286,11 @@ public void updateProductTest() { DrinkEto drink = TestData.createDrink(null, "Wasser", null, false); DrinkEto productToUpdate = - this.chief.post(drink, RestUrls.OfferManagement.Product.getCreateProductUrl(), DrinkEto.class); + this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); productToUpdate.setName(drink.getName() + "2"); - this.chief.post(productToUpdate, RestUrls.OfferManagement.Product.getCreateProductUrl(), DrinkEto.class); + this.chief.post(productToUpdate, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); ResponseData product = - this.chief.get(RestUrls.OfferManagement.Product.getFindProductUrl(productToUpdate.getId()), ProductEto.class); + this.chief.get(RestUrls.Offermanagement.Product.getFindProductUrl(productToUpdate.getId()), ProductEto.class); assertThat(product.getResponse().getStatus(), is(200)); assertThat(product.getResponseObject().getName(), is(productToUpdate.getName())); @@ -304,9 +304,9 @@ public void isProductInUseTest() { Long drinkId = createDrink().getId(); this.chief.post(TestData.createOffer(null, "some description", OfferState.NORMAL, null, null, drinkId, 0, - new Money(new BigDecimal(2.5))), RestUrls.OfferManagement.Offer.getCreateOfferUrl(), OfferEto.class); + new Money(new BigDecimal(2.5))), RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); ResponseData isproductInUse = - this.waiter.get(RestUrls.OfferManagement.Product.getIsProductInUseByOfferUrl(drinkId), Boolean.class); + this.waiter.get(RestUrls.Offermanagement.Product.getIsProductInUseByOfferUrl(drinkId), Boolean.class); assertThat(isproductInUse.getResponseObject(), is(true)); } @@ -320,7 +320,7 @@ public void getFilteredOffersTest() { OfferSortBy sortBy = new OfferSortBy(); List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Offer.getFilteredOffers(sortBy), OfferEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Offer.getFilteredOffers(sortBy), OfferEto.class); assertThat(offer.size(), is(DB.ALL_OFFERS.size())); } @@ -334,7 +334,7 @@ public void getFilteredProductsTest() { ProductSortBy sortBy = new ProductSortBy(); List> offer = - this.waiter.getAll(RestUrls.OfferManagement.Product.getFilteredProducts(sortBy), ProductEto.class); + this.waiter.getAll(RestUrls.Offermanagement.Product.getFilteredProducts(sortBy), ProductEto.class); assertThat(offer.size(), is(DB.ALL_PRODUCTS.size())); } } From 9348ae330f149d47a8eb1679adbb090c38901e98 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Mon, 29 Jun 2015 11:44:29 +0200 Subject: [PATCH 09/18] reconfigured WeeklyPeriod to be an embeddable --- .../dataaccess/api/SpecialEntity.java | 19 +++++++++---------- ...ntity.java => WeeklyPeriodEmbeddable.java} | 11 +++-------- 2 files changed, 12 insertions(+), 18 deletions(-) rename oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/{WeeklyPeriodEntity.java => WeeklyPeriodEmbeddable.java} (91%) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index 05f7fae70..0f545a89a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -4,11 +4,10 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; +import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.Table; -import org.hibernate.envers.Audited; - /** * The {@link ApplicationPersistenceEntity persistent entity} for a special. * @@ -16,12 +15,12 @@ */ @Entity(name = "Special") @Table(name = "Special") -@Audited public class SpecialEntity { private OfferEntity offer; - private WeeklyPeriodEntity activePeriod; + @Embedded + private WeeklyPeriodEmbeddable activePeriod; private Money specialPrice; @@ -46,21 +45,21 @@ public void setOffer(OfferEntity offer) { } /** - * Returns the {@link WeeklyPeriodEntity active period} this special applies for. + * Returns the {@link WeeklyPeriodEmbeddable active period} this special applies for. * - * @return activePeriod the {@link WeeklyPeriodEntity active period} this special applies for. + * @return activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. */ - public WeeklyPeriodEntity getActivePeriod() { + public WeeklyPeriodEmbeddable getActivePeriod() { return this.activePeriod; } /** - * Sets the {@link WeeklyPeriodEntity active period} this special applies for. + * Sets the {@link WeeklyPeriodEmbeddable active period} this special applies for. * - * @param activePeriod the {@link WeeklyPeriodEntity active period} this special applies for. + * @param activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. */ - public void setActivePeriod(WeeklyPeriodEntity activePeriod) { + public void setActivePeriod(WeeklyPeriodEmbeddable activePeriod) { this.activePeriod = activePeriod; } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java similarity index 91% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java rename to oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java index 0428b9b1b..857ff8254 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java @@ -2,23 +2,18 @@ import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.DayOfWeek; -import javax.persistence.Entity; -import javax.persistence.Table; +import javax.persistence.Embeddable; import javax.validation.constraints.Max; import javax.validation.constraints.Min; -import org.hibernate.envers.Audited; - /** * Weekly period describing a starting and an ending point. Each is defined as a fixed hour (24h-format) at a specific * day of week. * * @author mbrunnli */ -@Entity(name = "WeeklyPeriod") -@Table(name = "WeeklyPeriod") -@Audited -public class WeeklyPeriodEntity { +@Embeddable +public class WeeklyPeriodEmbeddable { private DayOfWeek startingDay; From 34a6a44ffcbc73dfc645b2c728cfebd25e2f0a35 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Mon, 29 Jun 2015 17:02:44 +0200 Subject: [PATCH 10/18] Unqiue field name for specials introduced --- .../dataaccess/api/SpecialEntity.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index 0f545a89a..ddcda9374 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -4,6 +4,7 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; +import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.Table; @@ -17,6 +18,8 @@ @Table(name = "Special") public class SpecialEntity { + private String name; + private OfferEntity offer; @Embedded @@ -24,6 +27,27 @@ public class SpecialEntity { private Money specialPrice; + /** + * Returns the name of this special. + * + * @return name the name of this special. + */ + @Column(unique = true) + public String getName() { + + return this.name; + } + + /** + * Sets the name of this special. + * + * @param name the name of this special. + */ + public void setName(String name) { + + this.name = name; + } + /** * Returns the {@link Offer} this special applies for. * From 687d3e792865b57c7739d04ce55b92e929e5233c Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Wed, 1 Jul 2015 11:47:29 +0200 Subject: [PATCH 11/18] Offer management refactored --- .../logic/impl/UcManageBinaryObjectImpl.java | 2 + .../offermanagement/common/api/Offer.java | 8 +- .../logic/api/Offermanagement.java | 219 +--------- .../logic/api/usecase/UcFindOffer.java | 58 +++ .../logic/api/usecase/UcFindProduct.java | 121 ++++++ .../logic/api/usecase/UcManageOffer.java | 28 ++ .../logic/api/usecase/UcManageProduct.java | 58 +++ .../logic/base/usecase/AbstractOfferUc.java | 37 ++ .../logic/base/usecase/AbstractProductUc.java | 109 +++++ .../logic/impl/OffermanagementImpl.java | 374 ++++-------------- .../logic/impl/usecase/UcFindOfferImpl.java | 119 ++++++ .../logic/impl/usecase/UcFindProductImpl.java | 183 +++++++++ .../logic/impl/usecase/UcManageOfferImpl.java | 52 +++ .../impl/usecase/UcManageProductImpl.java | 174 ++++++++ .../rest/OffermanagementRestServiceImpl.java | 2 + 15 files changed, 1024 insertions(+), 520 deletions(-) create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java create mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java index 35a8c7cab..498c7422f 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java @@ -2,6 +2,7 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.BinaryObjectEntity; import io.oasp.gastronomy.restaurant.general.dataaccess.api.dao.BinaryObjectDao; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; @@ -17,6 +18,7 @@ * @author sspielma */ @Named +@UseCase public class UcManageBinaryObjectImpl extends AbstractUc implements UcManageBinaryObject { /** @see #binaryObjectDao */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java index 72fda53cf..189390ece 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java @@ -35,8 +35,8 @@ public interface Offer extends MenuItem { void setPrice(Money price); /** - * @return is the {@link Meal#getId() ID} of the {@link Meal} or {@code null} if no {@link Meal} is contained in - * this {@link Offer}. + * @return is the {@link Meal#getId() ID} of the {@link Meal} or {@code null} if no {@link Meal} is contained in this + * {@link Offer}. */ Long getMealId(); @@ -46,8 +46,8 @@ public interface Offer extends MenuItem { void setMealId(Long mealId); /** - * @return is the {@link Drink#getId() ID} of the {@link Drink} or {@code null} if no {@link Drink} is contained - * in this {@link Offer}. + * @return is the {@link Drink#getId() ID} of the {@link Drink} or {@code null} if no {@link Drink} is contained in + * this {@link Offer}. */ Long getDrinkId(); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java index 44225ed02..5a23e6ab8 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java @@ -1,224 +1,15 @@ package io.oasp.gastronomy.restaurant.offermanagement.logic.api; -import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.module.jpa.common.api.to.PaginatedListTo; - -import java.sql.Blob; -import java.util.List; - -import javax.validation.Valid; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; /** * Interface for Offermanagement. * * @author loverbec */ -public interface Offermanagement { - - /** - * Gets an {@link OfferEto} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. - */ - OfferEto findOffer(Long id); - - /** - * Gets an {@link OfferCto} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. - */ - OfferCto findOfferCto(Long id); - - /** - * @return the {@link List} with all available {@link OfferEto}s. - */ - List findAllOffers(); - - /** - * Returns a list of offers matching the search criteria. - * - * @param criteria the {@link OfferSearchCriteriaTo}. - * @return the {@link List} of matching {@link OfferEto}s. - */ - PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria); - - /** - * Checks, whether a given {@link ProductEto} is in use by at least one {@link OfferEto}. - * - * @param product product to check if it is in use - * @return {@code true}, if there are no {@link OfferEto offers}, that use the given {@link ProductEto}. {@code false} - * otherwise. - */ - boolean isProductInUseByOffer(ProductEto product); - - /** - * @param offerFilterBo is the {@link OfferFilter offers filter criteria} - * @param sortBy is the {@link OfferSortBy} attribute, which defines the sorting. - * - * @return the {@link List} with all {@link OfferEto}s that match the {@link OfferFilter} criteria. - */ - List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy); - - /** - * Deletes an {@link OfferEto} by its {@link OfferEto#getId() id}. - * - * @param offerId is the {@link OfferEto#getId() id} that identifies the {@link OfferEto} to be deleted. - */ - void deleteOffer(Long offerId); - - /** - * If no ID is contained creates the {@link OfferEto} for the first time. Else it updates the {@link OfferEto} with - * given ID. If no {@link OfferEto} with given ID is present, an exception will be thrown. - * - * @param offer the {@link OfferEto} to persist. - * @return the generated/updated offer - */ - OfferEto saveOffer(@Valid OfferEto offer); - - /** - * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product#getId() product ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} or {@code null} if - * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} exists. - */ - ProductEto findProduct(Long id); - - /** - * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} with a specific revision using its - * entity identifier and a revision. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product#getId() product ID}. - * @param revision is the revision of the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product - * Product} - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} or {@code null} if - * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} exists. - */ - ProductEto findProductByRevision(Long id, Number revision); - - /** - * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal#getId() product ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} exists. - */ - MealEto findMeal(Long id); - - /** - * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink#getId() product ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} exists. - */ - DrinkEto findDrink(Long id); - - /** - * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish#getId() product ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} or {@code null} if - * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} exists. - */ - SideDishEto findSideDish(Long id); - - /** - * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product}s. - */ - List findAllProducts(); - - /** - * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal meals}. - */ - List findAllMeals(); - - /** - * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink drinks}. - */ - List findAllDrinks(); - - /** - * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish side - * dishes}. - */ - List findAllSideDishes(); - - /** - * Returns the {@link List} of filtered products sorted according to the specification. - * - * @param productFilterBo filter specification - * @param sortBy sorting specification - * @return a {@link List} of filtered products - */ - List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy); - - /** - * @param productId the ID of the {@link ProductEto} to get the picture - * @return the {@link BinaryObjectEto} that contains meta data about the picture - */ - BinaryObjectEto findProductPicture(Long productId); - - /** - * Returns a list of products matching the search criteria. - * - * @param criteria the {@link ProductSearchCriteriaTo}. - * @return the {@link List} of matching {@link ProductEto}s. - */ - PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria); - - /** - * @param productId the ID of the {@link ProductEto} to get the picture data - * @return the {@link Blob} that contains the data - */ - Blob findProductPictureBlob(Long productId); - - /** - * If no ID is contained creates the {@link ProductEto} for the first time. Else it updates the {@link ProductEto} - * with given ID. If no {@link ProductEto} with given ID is present, an exception will be thrown. - * - * @param product the {@link ProductEto} to persist. - * @return the persisted {@link ProductEto}. - */ - ProductEto saveProduct(ProductEto product); - - /** - * Deletes a {@link ProductEto}. - * - * @param productId is the ID of the {@link ProductEto} to delete - */ - void deleteProduct(Long productId); - - /** - * Updates the picture of the product. - * - * @param productId is the ID of the {@link ProductEto} to update the picture - * @param blob is the binary representation of the picture - * @param binaryObjectEto is the mimeType of the blob - */ - void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto); - - /** - * Deletes the Picture of the {@link ProductEto}. - * - * @param productId is the ID of the {@link ProductEto} to delte the picture - */ - void deleteProductPicture(Long productId); +public interface Offermanagement extends UcFindOffer, UcManageOffer, UcManageProduct, UcFindProduct { } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java new file mode 100644 index 000000000..a065576e4 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java @@ -0,0 +1,58 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; + +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +import java.util.List; + +/** + * Interface of UcFindOffer to centralize documentation and signatures of methods. + * + * @author mbrunnli + * @since dev + */ +public interface UcFindOffer { + + /** + * Gets an {@link OfferEto} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. + */ + OfferEto findOffer(Long id); + + /** + * Gets an {@link OfferCto} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. + */ + OfferCto findOfferCto(Long id); + + /** + * @return the {@link List} with all available {@link OfferEto}s. + */ + List findAllOffers(); + + /** + * Returns a list of offers matching the search criteria. + * + * @param criteria the {@link OfferSearchCriteriaTo}. + * @return the {@link List} of matching {@link OfferEto}s. + */ + PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria); + + /** + * @param offerFilterBo is the {@link OfferFilter offers filter criteria} + * @param sortBy is the {@link OfferSortBy} attribute, which defines the sorting. + * @return the {@link List} with all {@link OfferEto}s that match the {@link OfferFilter} criteria. + */ + List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy); + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java new file mode 100644 index 000000000..df9973ba2 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java @@ -0,0 +1,121 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; + +import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +import java.sql.Blob; +import java.util.List; + +/** + * Interface of UcFindProduct to centralize documentation and signatures of methods. + * + * @author mbrunnli + * @since dev + */ +public interface UcFindProduct { + + /** + * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product#getId() product ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} or {@code null} if + * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} exists. + */ + ProductEto findProduct(Long id); + + /** + * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} with a specific revision using its + * entity identifier and a revision. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product#getId() product ID}. + * @param revision is the revision of the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product + * Product} + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} or {@code null} if + * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} exists. + */ + ProductEto findProductByRevision(Long id, Number revision); + + /** + * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal#getId() product ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal} exists. + */ + MealEto findMeal(Long id); + + /** + * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink#getId() product ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} exists. + */ + DrinkEto findDrink(Long id); + + /** + * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish#getId() product ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} or {@code null} if + * no such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish} exists. + */ + SideDishEto findSideDish(Long id); + + /** + * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product}s. + */ + List findAllProducts(); + + /** + * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal meals}. + */ + List findAllMeals(); + + /** + * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink drinks}. + */ + List findAllDrinks(); + + /** + * @return the {@link List} with all {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish side + * dishes}. + */ + List findAllSideDishes(); + + /** + * Returns the {@link List} of filtered products sorted according to the specification. + * + * @param productFilterBo filter specification + * @param sortBy sorting specification + * @return a {@link List} of filtered products + */ + List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy); + + /** + * @param productId the ID of the {@link ProductEto} to get the picture + * @return the {@link BinaryObjectEto} that contains meta data about the picture + */ + BinaryObjectEto findProductPicture(Long productId); + + /** + * Returns a list of products matching the search criteria. + * + * @param criteria the {@link ProductSearchCriteriaTo}. + * @return the {@link List} of matching {@link ProductEto}s. + */ + PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria); + + /** + * @param productId the ID of the {@link ProductEto} to get the picture data + * @return the {@link Blob} that contains the data + */ + Blob findProductPictureBlob(Long productId); +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java new file mode 100644 index 000000000..d3b55df3c --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java @@ -0,0 +1,28 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; + +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; + +import javax.validation.Valid; + +/** + * Interface of UcManageOffer to centralize documentation and signatures of methods. + */ +public interface UcManageOffer { + + /** + * Deletes an {@link OfferEto} by its {@link OfferEto#getId() id}. + * + * @param offerId is the {@link OfferEto#getId() id} that identifies the {@link OfferEto} to be deleted. + */ + void deleteOffer(Long offerId); + + /** + * If no ID is contained creates the {@link OfferEto} for the first time. Else it updates the {@link OfferEto} with + * given ID. If no {@link OfferEto} with given ID is present, an exception will be thrown. + * + * @param offer the {@link OfferEto} to persist. + * @return the generated/updated offer + */ + OfferEto saveOffer(@Valid OfferEto offer); + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java new file mode 100644 index 000000000..aaa11e286 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java @@ -0,0 +1,58 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; + +import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; + +import java.sql.Blob; + +/** + * Interface of UcManageProduct to centralize documentation and signatures of methods. + * + * @author mbrunnli + * @since dev + */ +public interface UcManageProduct { + + /** + * Checks, whether a given {@link ProductEto} is in use by at least one {@link OfferEto}. + * + * @param product product to check if it is in use + * @return {@code true}, if there are no {@link OfferEto offers}, that use the given {@link ProductEto}. {@code false} + * otherwise. + */ + boolean isProductInUseByOffer(ProductEto product); + + /** + * If no ID is contained creates the {@link ProductEto} for the first time. Else it updates the {@link ProductEto} + * with given ID. If no {@link ProductEto} with given ID is present, an exception will be thrown. + * + * @param product the {@link ProductEto} to persist. + * @return the persisted {@link ProductEto}. + */ + ProductEto saveProduct(ProductEto product); + + /** + * Deletes a {@link ProductEto}. + * + * @param productId is the ID of the {@link ProductEto} to delete + */ + void deleteProduct(Long productId); + + /** + * Updates the picture of the product. + * + * @param productId is the ID of the {@link ProductEto} to update the picture + * @param blob is the binary representation of the picture + * @param binaryObjectEto is the mimeType of the blob + */ + void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto); + + /** + * Deletes the Picture of the {@link ProductEto}. + * + * @param productId is the ID of the {@link ProductEto} to delte the picture + */ + void deleteProductPicture(Long productId); + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java new file mode 100644 index 000000000..5b7fc9019 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java @@ -0,0 +1,37 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase; + +import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.OfferDao; + +import javax.inject.Inject; + +/** + * Abstract use case for Offers, which provides access to the commonly necessary data access objects. + */ +public class AbstractOfferUc extends AbstractUc { + + /** @see #getOfferDao() */ + private OfferDao offerDao; + + /** + * Returns the field 'offerDao'. + * + * @return the {@link OfferDao} instance. + */ + public OfferDao getOfferDao() { + + return this.offerDao; + } + + /** + * Sets the field 'offerDao'. + * + * @param offerDao New value for offerDao + */ + @Inject + public void setOfferDao(OfferDao offerDao) { + + this.offerDao = offerDao; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java new file mode 100644 index 000000000..b06dd2b5f --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java @@ -0,0 +1,109 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase; + +import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.MealDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.ProductDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.SideDishDao; + +import javax.inject.Inject; + +/** + * Abstract use case for Products, which provides access to the commonly necessary data access objects. + * + * @author mbrunnli + * @since dev + */ +public abstract class AbstractProductUc extends AbstractUc { + + /** + * @see #setProductDao(ProductDao) + */ + private ProductDao productDao; + + /** + * @see #setMealDao(MealDao) + */ + private MealDao mealDao; + + /** + * @see #setDrinkDao(DrinkDao) + */ + private DrinkDao drinkDao; + + /** + * @see #setSideDishDao(SideDishDao) + */ + private SideDishDao sideDishDao; + + /** + * @return productDao + */ + public ProductDao getProductDao() { + + return this.productDao; + } + + /** + * @return mealDao + */ + public MealDao getMealDao() { + + return this.mealDao; + } + + /** + * @return drinkDao + */ + public DrinkDao getDrinkDao() { + + return this.drinkDao; + } + + /** + * @return sideDishDao + */ + public SideDishDao getSideDishDao() { + + return this.sideDishDao; + } + + /** + * Sets the field 'productDao'. + * + * @param productDao New value for productDao + */ + @Inject + public void setProductDao(ProductDao productDao) { + + this.productDao = productDao; + } + + /** + * @param mealDao the {@link MealDao} to {@link Inject}. + */ + @Inject + public void setMealDao(MealDao mealDao) { + + this.mealDao = mealDao; + } + + /** + * @param drinkDao the {@link DrinkDao} to {@link Inject}. + */ + @Inject + public void setDrinkDao(DrinkDao drinkDao) { + + this.drinkDao = drinkDao; + } + + /** + * @param sideDishDao the {@link SideDishDao} to {@link Inject}. + */ + @Inject + public void setSideDishDao(SideDishDao sideDishDao) { + + this.sideDishDao = sideDishDao; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java index 0bb9decd2..1bbb69b91 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java @@ -1,18 +1,8 @@ package io.oasp.gastronomy.restaurant.offermanagement.logic.impl; -import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; import io.oasp.gastronomy.restaurant.general.logic.base.AbstractComponentFacade; -import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductType; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.exception.OfferEmptyException; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.MealDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.OfferDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.ProductDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.SideDishDao; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; @@ -26,19 +16,17 @@ import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.sql.Blob; -import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import javax.annotation.security.RolesAllowed; import javax.inject.Inject; import javax.inject.Named; -import javax.validation.Valid; - -import net.sf.mmm.util.exception.api.ObjectMismatchException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,23 +41,13 @@ public class OffermanagementImpl extends AbstractComponentFacade implements Offe private static final Logger LOG = LoggerFactory.getLogger(OffermanagementImpl.class); - /** @see #getOfferDao() */ - private OfferDao offerDao; - - /** @see #setProductDao(ProductDao) */ - private ProductDao productDao; - - /** @see #setMealDao(MealDao) */ - private MealDao mealDao; + private UcFindOffer ucFindOffer; - /** @see #setDrinkDao(DrinkDao) */ - private DrinkDao drinkDao; + private UcManageOffer ucManageOffer; - /** @see #setSideDishDao(SideDishDao) */ - private SideDishDao sideDishDao; + private UcFindProduct ucFindProduct; - /** **/ - private UcManageBinaryObject ucManageBinaryObject; + private UcManageProduct ucManageProduct; /** * The constructor. @@ -80,405 +58,197 @@ public OffermanagementImpl() { } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) public OfferEto findOffer(Long id) { - LOG.debug("Get OfferEto with id '{}' from database.", id); - return getBeanMapper().map(getOfferDao().findOne(id), OfferEto.class); + return this.ucFindOffer.findOffer(id); } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) public OfferCto findOfferCto(Long id) { - LOG.debug("Get OfferCTO with id '{}' from database.", id); - OfferCto result = new OfferCto(); - // offer - OfferEto offerEto = findOffer(id); - if (offerEto == null) { - return null; - } - result.setOffer(offerEto); - // meal - Long mealId = offerEto.getMealId(); - if (mealId != null) { - result.setMeal(findMeal(mealId)); - } - // drink - Long drinkId = offerEto.getDrinkId(); - if (drinkId != null) { - result.setDrink(findDrink(drinkId)); - } - // sideDish - Long sideDishId = offerEto.getSideDishId(); - if (sideDishId != null) { - result.setSideDish(findSideDish(sideDishId)); - } - return result; + return this.ucFindOffer.findOfferCto(id); } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) public List findAllOffers() { - LOG.debug("Get all offers from database."); - return getBeanMapper().mapList(getOfferDao().findAll(), OfferEto.class); + return this.ucFindOffer.findAllOffers(); } @Override - @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) - public boolean isProductInUseByOffer(ProductEto product) { + public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { - LOG.debug("Get all offers from database for the given product with id '" + product.getId() + "'."); - - List persistedOffers = findAllOffers(); - - /* - * Check the occurrence of a product within all offers. Therefore, only check for a instance of a product type - * product type. - */ - ProductType productType = null; - - if (product instanceof DrinkEto) { - LOG.debug("The given product is an instance of Drink '" + product.getDescription() + "', id '" + product.getId() - + "'. Check all Offer-Drinks for that given occurrence."); - productType = ProductType.DRINK; - } else if (product instanceof MealEto) { - LOG.debug("The given product is an instance of Meal '" + product.getDescription() + "', id '" + product.getId() - + "'. Check all Offer-Meals for that given occurrence."); - productType = ProductType.MEAL; - } else if (product instanceof SideDishEto) { - LOG.debug("The given product is an instance of SideDish '" + product.getDescription() + "', id '" - + product.getId() + "'. Check all Offer-SideDishes for that given occurrence."); - productType = ProductType.SIDEDISH; - } - - if (productType == null) { - LOG.debug("The given product not in use by an offer."); - return false; - } - - for (OfferEto offer : persistedOffers) { - - if (productType.isDrink()) { - if (Objects.equals(offer.getDrinkId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - - } - - if (productType.isMeal()) { - if (Objects.equals(offer.getMealId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - } - - if (productType.isSideDish()) { - if (Objects.equals(offer.getSideDishId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - } - } - - LOG.debug("The given product not in use by an offer."); - return false; + return this.ucFindOffer.findOfferEtos(criteria); } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { - List offers = getOfferDao().findOffersFiltered(offerFilterBo, sortBy); - LOG.debug("'" + offers.size() + "' offers fetched."); - - List offerBos = new ArrayList<>(offers.size()); - for (OfferEntity o : offers) { - offerBos.add(getBeanMapper().map(o, OfferEto.class)); - } - return offerBos; + return this.ucFindOffer.findOffersFiltered(offerFilterBo, sortBy); } @Override - @RolesAllowed(PermissionConstants.DELETE_OFFER) public void deleteOffer(Long offerId) { - getOfferDao().delete(offerId); + this.ucManageOffer.deleteOffer(offerId); } @Override - @RolesAllowed(PermissionConstants.SAVE_OFFER) - public OfferEto saveOffer(@Valid OfferEto offer) { - - Objects.requireNonNull(offer, "offer"); + public OfferEto saveOffer(OfferEto offer) { - if ((offer.getMealId() == null) && (offer.getDrinkId() == null) && (offer.getSideDishId() == null)) { - throw new OfferEmptyException(offer); - } else { - OfferEntity persistedOffer = getOfferDao().save(getBeanMapper().map(offer, OfferEntity.class)); - return getBeanMapper().map(persistedOffer, OfferEto.class); - } + return this.ucManageOffer.saveOffer(offer); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public ProductEto findProduct(Long id) { - - LOG.debug("Get Product with id '" + id + "' from database."); - ProductEntity product = getProductDao().findOne(id); - if (product == null) { - return null; - } else { - return getBeanMapper().map(product, ProductEto.class); - } - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public MealEto findMeal(Long id) { + public boolean isProductInUseByOffer(ProductEto product) { - ProductEto product = findProduct(id); - try { - return (MealEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, MealEto.class, e); - } + return this.ucManageProduct.isProductInUseByOffer(product); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public DrinkEto findDrink(Long id) { + public ProductEto saveProduct(ProductEto product) { - ProductEto product = findProduct(id); - try { - return (DrinkEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, DrinkEto.class, e); - } + return this.ucManageProduct.saveProduct(product); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public SideDishEto findSideDish(Long id) { + public void deleteProduct(Long productId) { - ProductEto product = findProduct(id); - try { - return (SideDishEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, SideDishEto.class, e); - } + this.ucManageProduct.deleteProduct(productId); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllProducts() { + public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { - LOG.debug("Get all products from database."); - return getBeanMapper().mapList(getProductDao().findAll(), ProductEto.class); + this.ucManageProduct.updateProductPicture(productId, blob, binaryObjectEto); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllMeals() { + public void deleteProductPicture(Long productId) { - LOG.debug("Get all meals with from database."); - return getBeanMapper().mapList(this.mealDao.findAll(), MealEto.class); + this.ucManageProduct.deleteProductPicture(productId); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllDrinks() { + public ProductEto findProduct(Long id) { - LOG.debug("Get all drinks with from database."); - return getBeanMapper().mapList(this.drinkDao.findAll(), DrinkEto.class); + return this.ucFindProduct.findProduct(id); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllSideDishes() { + public ProductEto findProductByRevision(Long id, Number revision) { - LOG.debug("Get all sidedishes with from database."); - return getBeanMapper().mapList(this.sideDishDao.findAll(), SideDishEto.class); + return this.ucFindProduct.findProductByRevision(id, revision); } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { + public MealEto findMeal(Long id) { - LOG.debug("Fetch filtered offers."); - return getBeanMapper().mapList(getProductDao().findProductsFiltered(productFilterBo, sortBy), ProductEto.class); + return this.ucFindProduct.findMeal(id); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public BinaryObjectEto findProductPicture(Long productId) { + public DrinkEto findDrink(Long id) { - return getUcManageBinaryObject().findBinaryObject(findProduct(productId).getPictureId()); + return this.ucFindProduct.findDrink(id); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) - public Blob findProductPictureBlob(Long productId) { + public SideDishEto findSideDish(Long id) { - return getUcManageBinaryObject().getBinaryObjectBlob(findProductPicture(productId).getId()); + return this.ucFindProduct.findSideDish(id); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) - public ProductEto findProductByRevision(Long id, Number revision) { + public List findAllProducts() { - LOG.debug("Get Product with id '" + id + "' and revision '" + revision + "' from database."); - ProductEntity product = getProductDao().load(id, revision); - if (product == null) { - return null; - } else { - return getBeanMapper().map(product, ProductEto.class); - } + return this.ucFindProduct.findAllProducts(); } @Override - @RolesAllowed(PermissionConstants.SAVE_PRODUCT) - public ProductEto saveProduct(ProductEto product) { - - Objects.requireNonNull(product, "product"); + public List findAllMeals() { - ProductEntity persistedProduct = getProductDao().save(getBeanMapper().map(product, ProductEntity.class)); - return getBeanMapper().map(persistedProduct, ProductEto.class); + return this.ucFindProduct.findAllMeals(); } @Override - @RolesAllowed(PermissionConstants.DELETE_PRODUCT) - public void deleteProduct(Long productId) { + public List findAllDrinks() { - getProductDao().delete(productId); + return this.ucFindProduct.findAllDrinks(); } @Override - @RolesAllowed(PermissionConstants.SAVE_PRODUCT_PICTURE) - public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { - - ProductEntity product = getProductDao().findOne(productId); - binaryObjectEto = getUcManageBinaryObject().saveBinaryObject(blob, binaryObjectEto); - product.setPictureId(binaryObjectEto.getId()); - getProductDao().save(product); + public List findAllSideDishes() { + return this.ucFindProduct.findAllSideDishes(); } @Override - @RolesAllowed(PermissionConstants.DELETE_PRODUCT_PICTURE) - public void deleteProductPicture(Long productId) { - - ProductEntity product = getProductDao().findOne(productId); - getUcManageBinaryObject().deleteBinaryObject(product.getPictureId()); + public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { + return this.ucFindProduct.findProductsFiltered(productFilterBo, sortBy); } @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { + public BinaryObjectEto findProductPicture(Long productId) { - criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); - PaginatedListTo offers = getOfferDao().findOffers(criteria); - return mapPaginatedEntityList(offers, OfferEto.class); + return this.ucFindProduct.findProductPicture(productId); } @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) public PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria) { - criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); - PaginatedListTo products = getProductDao().findProducts(criteria); - return mapPaginatedEntityList(products, ProductEto.class); + return this.ucFindProduct.findProductEtos(criteria); } - /** - * @return {@link OfferDao} instance. - */ - public OfferDao getOfferDao() { + @Override + public Blob findProductPictureBlob(Long productId) { - return this.offerDao; + return this.ucFindProduct.findProductPictureBlob(productId); } /** - * Sets the field 'offerDao'. + * Sets the field 'ucFindOffer'. * - * @param offerDao New value for offerDao - */ - @Inject - public void setOfferDao(OfferDao offerDao) { - - this.offerDao = offerDao; - } - - /** - * @param ucManageBinaryObject the ucManageBinaryObject to set + * @param ucFindOffer New value for ucFindOffer */ @Inject - public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { - - this.ucManageBinaryObject = ucManageBinaryObject; - } - - /** - * @return ucManageBinaryObject - */ - public UcManageBinaryObject getUcManageBinaryObject() { - - return this.ucManageBinaryObject; - } + @UseCase + public void setUcFindOffer(UcFindOffer ucFindOffer) { - /** - * @return productDao - */ - public ProductDao getProductDao() { - - return this.productDao; + this.ucFindOffer = ucFindOffer; } /** - * Sets the field 'productDao'. + * Sets the field 'ucManageOffer'. * - * @param productDao New value for productDao - */ - @Inject - public void setProductDao(ProductDao productDao) { - - this.productDao = productDao; - } - - /** - * @param mealDao the {@link MealDao} to {@link Inject}. + * @param ucManageOffer New value for ucManageOffer */ @Inject - public void setMealDao(MealDao mealDao) { + @UseCase + public void setUcManageOffer(UcManageOffer ucManageOffer) { - this.mealDao = mealDao; + this.ucManageOffer = ucManageOffer; } /** - * @param drinkDao the {@link DrinkDao} to {@link Inject}. + * @param ucFindProduct new value of {@link #getucFindProduct}. */ @Inject - public void setDrinkDao(DrinkDao drinkDao) { + @UseCase + public void setUcFindProduct(UcFindProduct ucFindProduct) { - this.drinkDao = drinkDao; + this.ucFindProduct = ucFindProduct; } /** - * @param sideDishDao the {@link SideDishDao} to {@link Inject}. + * @param ucManageProduct new value of {@link #getucManageProduct}. */ @Inject - public void setSideDishDao(SideDishDao sideDishDao) { + @UseCase + public void setUcManageProduct(UcManageProduct ucManageProduct) { - this.sideDishDao = sideDishDao; + this.ucManageProduct = ucManageProduct; } } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java new file mode 100644 index 000000000..9d3cf72f1 --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java @@ -0,0 +1,119 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; + +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; +import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractOfferUc; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; + +/** + * Use case implementation for searching, filtering and getting Offers + */ +@Named +@UseCase +@Validated +public class UcFindOfferImpl extends AbstractOfferUc implements UcFindOffer { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(UcFindOfferImpl.class); + + /** Use case for finding products */ + private UcFindProduct ucFindProduct; + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public OfferEto findOffer(Long id) { + + LOG.debug("Get OfferEto with id '{}' from database.", id); + return getBeanMapper().map(getOfferDao().findOne(id), OfferEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { + + criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); + PaginatedListTo offers = getOfferDao().findOffers(criteria); + return mapPaginatedEntityList(offers, OfferEto.class); + } + + @Override + @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) + public OfferCto findOfferCto(Long id) { + + LOG.debug("Get OfferCTO with id '{}' from database.", id); + OfferCto result = new OfferCto(); + // offer + OfferEto offerEto = findOffer(id); + if (offerEto == null) { + return null; + } + result.setOffer(offerEto); + // meal + Long mealId = offerEto.getMealId(); + if (mealId != null) { + result.setMeal(this.ucFindProduct.findMeal(mealId)); + } + // drink + Long drinkId = offerEto.getDrinkId(); + if (drinkId != null) { + result.setDrink(this.ucFindProduct.findDrink(drinkId)); + } + // sideDish + Long sideDishId = offerEto.getSideDishId(); + if (sideDishId != null) { + result.setSideDish(this.ucFindProduct.findSideDish(sideDishId)); + } + return result; + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public List findAllOffers() { + + LOG.debug("Get all offers from database."); + return getBeanMapper().mapList(getOfferDao().findAll(), OfferEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { + + List offers = getOfferDao().findOffersFiltered(offerFilterBo, sortBy); + LOG.debug("'" + offers.size() + "' offers fetched."); + + List offerBos = new ArrayList<>(offers.size()); + for (OfferEntity o : offers) { + offerBos.add(getBeanMapper().map(o, OfferEto.class)); + } + return offerBos; + } + + /** + * @param ucFindProduct new value of {@link #getucFindProduct}. + */ + @Inject + @UseCase + public void setUcFindProduct(UcFindProduct ucFindProduct) { + + this.ucFindProduct = ucFindProduct; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java new file mode 100644 index 000000000..38a1cd21f --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java @@ -0,0 +1,183 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; + +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; +import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; +import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; +import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractProductUc; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +import java.sql.Blob; +import java.util.List; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.inject.Named; + +import net.sf.mmm.util.exception.api.ObjectMismatchException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; + +/** + * Use case implementation for searching, filtering and getting Products. + * + * @author mbrunnli + * @since dev + */ +@Named +@UseCase +@Validated +public class UcFindProductImpl extends AbstractProductUc implements UcFindProduct { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(UcFindProductImpl.class); + + /** Use case for managing binary objects */ + private UcManageBinaryObject ucManageBinaryObject; + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public ProductEto findProduct(Long id) { + + LOG.debug("Get Product with id '" + id + "' from database."); + ProductEntity product = getProductDao().findOne(id); + if (product == null) { + return null; + } else { + return getBeanMapper().map(product, ProductEto.class); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public MealEto findMeal(Long id) { + + ProductEto product = findProduct(id); + try { + return (MealEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, MealEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public DrinkEto findDrink(Long id) { + + ProductEto product = findProduct(id); + try { + return (DrinkEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, DrinkEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public SideDishEto findSideDish(Long id) { + + ProductEto product = findProduct(id); + try { + return (SideDishEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, SideDishEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllProducts() { + + LOG.debug("Get all products from database."); + return getBeanMapper().mapList(getProductDao().findAll(), ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllMeals() { + + LOG.debug("Get all meals with from database."); + return getBeanMapper().mapList(getMealDao().findAll(), MealEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllDrinks() { + + LOG.debug("Get all drinks with from database."); + return getBeanMapper().mapList(getDrinkDao().findAll(), DrinkEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllSideDishes() { + + LOG.debug("Get all sidedishes with from database."); + return getBeanMapper().mapList(getSideDishDao().findAll(), SideDishEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria) { + + criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); + PaginatedListTo products = getProductDao().findProducts(criteria); + return mapPaginatedEntityList(products, ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { + + LOG.debug("Fetch filtered offers."); + return getBeanMapper().mapList(getProductDao().findProductsFiltered(productFilterBo, sortBy), ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public BinaryObjectEto findProductPicture(Long productId) { + + return this.ucManageBinaryObject.findBinaryObject(findProduct(productId).getPictureId()); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) + public Blob findProductPictureBlob(Long productId) { + + return this.ucManageBinaryObject.getBinaryObjectBlob(findProductPicture(productId).getId()); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) + public ProductEto findProductByRevision(Long id, Number revision) { + + LOG.debug("Get Product with id '" + id + "' and revision '" + revision + "' from database."); + ProductEntity product = getProductDao().load(id, revision); + if (product == null) { + return null; + } else { + return getBeanMapper().map(product, ProductEto.class); + } + } + + /** + * @param ucManageBinaryObject new value of {@link #getucManageBinaryObject}. + */ + @Inject + @UseCase + public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { + + this.ucManageBinaryObject = ucManageBinaryObject; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java new file mode 100644 index 000000000..97c2de54c --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java @@ -0,0 +1,52 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; + +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.exception.OfferEmptyException; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractOfferUc; + +import java.util.Objects; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Named; +import javax.validation.Valid; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; + +/** + * Use case implementation for modifying and deleting Offers + */ +@Named +@UseCase +@Validated +public class UcManageOfferImpl extends AbstractOfferUc implements UcManageOffer { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(UcManageOfferImpl.class); + + @Override + @RolesAllowed(PermissionConstants.DELETE_OFFER) + public void deleteOffer(Long offerId) { + + getOfferDao().delete(offerId); + } + + @Override + @RolesAllowed(PermissionConstants.SAVE_OFFER) + public OfferEto saveOffer(@Valid OfferEto offer) { + + Objects.requireNonNull(offer, "offer"); + + if ((offer.getMealId() == null) && (offer.getDrinkId() == null) && (offer.getSideDishId() == null)) { + throw new OfferEmptyException(offer); + } else { + OfferEntity persistedOffer = getOfferDao().save(getBeanMapper().map(offer, OfferEntity.class)); + return getBeanMapper().map(persistedOffer, OfferEto.class); + } + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java new file mode 100644 index 000000000..c2d7b116b --- /dev/null +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java @@ -0,0 +1,174 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; + +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; +import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; +import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductType; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; +import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractProductUc; + +import java.sql.Blob; +import java.util.List; +import java.util.Objects; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; + +/** + * Use case implementation for modifying and deleting Offers + * + * @author mbrunnli + * @since dev + */ +@Named +@UseCase +@Validated +public class UcManageProductImpl extends AbstractProductUc implements UcManageProduct { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(UcManageProductImpl.class); + + /** Use case to find Offers */ + private UcFindOffer ucFindOffer; + + /** Use case for managing binary objects */ + private UcManageBinaryObject ucManageBinaryObject; + + @Override + @RolesAllowed(PermissionConstants.SAVE_PRODUCT) + public ProductEto saveProduct(ProductEto product) { + + Objects.requireNonNull(product, "product"); + + ProductEntity persistedProduct = getProductDao().save(getBeanMapper().map(product, ProductEntity.class)); + return getBeanMapper().map(persistedProduct, ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.DELETE_PRODUCT) + public void deleteProduct(Long productId) { + + getProductDao().delete(productId); + } + + @Override + @RolesAllowed(PermissionConstants.SAVE_PRODUCT_PICTURE) + public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { + + ProductEntity product = getProductDao().findOne(productId); + binaryObjectEto = this.ucManageBinaryObject.saveBinaryObject(blob, binaryObjectEto); + product.setPictureId(binaryObjectEto.getId()); + getProductDao().save(product); + + } + + @Override + @RolesAllowed(PermissionConstants.DELETE_PRODUCT_PICTURE) + public void deleteProductPicture(Long productId) { + + ProductEntity product = getProductDao().findOne(productId); + this.ucManageBinaryObject.deleteBinaryObject(product.getPictureId()); + + } + + @Override + @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) + public boolean isProductInUseByOffer(ProductEto product) { + + LOG.debug("Get all offers from database for the given product with id '" + product.getId() + "'."); + + List persistedOffers = this.ucFindOffer.findAllOffers(); + + /* + * Check the occurrence of a product within all offers. Therefore, only check for a instance of a product type + * product type. + */ + ProductType productType = null; + + if (product instanceof DrinkEto) { + LOG.debug("The given product is an instance of Drink '" + product.getDescription() + "', id '" + product.getId() + + "'. Check all Offer-Drinks for that given occurrence."); + productType = ProductType.DRINK; + } else if (product instanceof MealEto) { + LOG.debug("The given product is an instance of Meal '" + product.getDescription() + "', id '" + product.getId() + + "'. Check all Offer-Meals for that given occurrence."); + productType = ProductType.MEAL; + } else if (product instanceof SideDishEto) { + LOG.debug("The given product is an instance of SideDish '" + product.getDescription() + "', id '" + + product.getId() + "'. Check all Offer-SideDishes for that given occurrence."); + productType = ProductType.SIDEDISH; + } + + if (productType == null) { + LOG.debug("The given product not in use by an offer."); + return false; + } + + for (OfferEto offer : persistedOffers) { + + if (productType.isDrink()) { + if (Objects.equals(offer.getDrinkId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + + } + + if (productType.isMeal()) { + if (Objects.equals(offer.getMealId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + } + + if (productType.isSideDish()) { + if (Objects.equals(offer.getSideDishId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + } + } + + LOG.debug("The given product not in use by an offer."); + return false; + } + + /** + * @param ucManageBinaryObject new value of {@link #getucManageBinaryObject}. + */ + @Inject + @UseCase + public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { + + this.ucManageBinaryObject = ucManageBinaryObject; + } + + /** + * @param ucFindOffer new value of {@link #getucFindOffer}. + */ + @Inject + @UseCase + public void setUcFindOffer(UcFindOffer ucFindOffer) { + + this.ucFindOffer = ucFindOffer; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java index 28d201c1d..ebbb78a58 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java @@ -13,6 +13,8 @@ import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.io.ByteArrayInputStream; From f5d84480c10d989fc1a4075ff23a250e1a6adaa0 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Mon, 13 Jul 2015 16:05:20 +0200 Subject: [PATCH 12/18] Adapted to latest oasp4j release --- .../offermanagement/logic/api/to/OfferSortBy.java | 10 +++++----- .../offermanagement/logic/api/to/ProductSortBy.java | 10 +++++----- .../dataaccess/impl/dao/TableDaoImpl.java | 8 ++++---- pom.xml | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java index 174f2dad9..0aaf85cd7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java @@ -1,7 +1,7 @@ package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferSortByHitEntry; -import io.oasp.module.jpa.common.api.to.OrderBy; +import io.oasp.module.jpa.common.api.to.OrderDirection; /** * @@ -11,7 +11,7 @@ public class OfferSortBy { private OfferSortByHitEntry sortByEntry; - private OrderBy orderBy; + private OrderDirection orderBy; /** * The constructor. @@ -19,7 +19,7 @@ public class OfferSortBy { public OfferSortBy() { this.sortByEntry = OfferSortByHitEntry.ID; - this.orderBy = OrderBy.ASC; + this.orderBy = OrderDirection.ASC; } /** @@ -47,7 +47,7 @@ public void setSortByEntry(OfferSortByHitEntry sortByEntry) { * * @return Value of orderBy */ - public OrderBy getOrderBy() { + public OrderDirection getOrderBy() { return this.orderBy; } @@ -57,7 +57,7 @@ public OrderBy getOrderBy() { * * @param orderBy New value for orderBy */ - public void setOrderBy(OrderBy orderBy) { + public void setOrderBy(OrderDirection orderBy) { this.orderBy = orderBy; } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java index 332848365..1a5b456f7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java @@ -1,7 +1,7 @@ package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductSortByHitEntry; -import io.oasp.module.jpa.common.api.to.OrderBy; +import io.oasp.module.jpa.common.api.to.OrderDirection; // TODO mvielsac javadoc for class is missing @@ -12,7 +12,7 @@ public class ProductSortBy { private ProductSortByHitEntry sortByEntry; - private OrderBy orderBy; + private OrderDirection orderBy; /** * Constructor for {@link ProductSortBy}. @@ -20,7 +20,7 @@ public class ProductSortBy { public ProductSortBy() { this.sortByEntry = ProductSortByHitEntry.ID; - this.orderBy = OrderBy.ASC; + this.orderBy = OrderDirection.ASC; } /** @@ -48,7 +48,7 @@ public void setSortByEntry(ProductSortByHitEntry sortByEntry) { * * @return Value of orderBy */ - public OrderBy getOrderBy() { + public OrderDirection getOrderBy() { return this.orderBy; } @@ -58,7 +58,7 @@ public OrderBy getOrderBy() { * * @param orderBy New value for orderBy */ - public void setOrderBy(OrderBy orderBy) { + public void setOrderBy(OrderDirection orderBy) { this.orderBy = orderBy; } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java index eac0b13e2..6560bcad7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java +++ b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java @@ -6,8 +6,8 @@ import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.TableEntity; import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.dao.TableDao; import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableSearchCriteriaTo; -import io.oasp.module.jpa.common.api.to.OrderBy; import io.oasp.module.jpa.common.api.to.OrderByTo; +import io.oasp.module.jpa.common.api.to.OrderDirection; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.util.List; @@ -80,7 +80,7 @@ private void addOrderBy(JPAQuery query, EntityPathBase alias, Table for (OrderByTo orderEntry : sort) { if ("number".equals(orderEntry.getName())) { - if (OrderBy.ASC.equals(orderEntry.getDirection())) { + if (OrderDirection.ASC.equals(orderEntry.getDirection())) { query.orderBy(Alias.$(table.getNumber()).asc()); } else { query.orderBy(Alias.$(table.getNumber()).desc()); @@ -88,7 +88,7 @@ private void addOrderBy(JPAQuery query, EntityPathBase alias, Table } else if ("waiterId".equals(orderEntry.getName())) { - if (OrderBy.ASC.equals(orderEntry.getDirection())) { + if (OrderDirection.ASC.equals(orderEntry.getDirection())) { query.orderBy(Alias.$(table.getWaiterId()).asc()); } else { query.orderBy(Alias.$(table.getWaiterId()).desc()); @@ -96,7 +96,7 @@ private void addOrderBy(JPAQuery query, EntityPathBase alias, Table } else if ("state".equals(orderEntry.getName())) { - if (OrderBy.ASC.equals(orderEntry.getDirection())) { + if (OrderDirection.ASC.equals(orderEntry.getDirection())) { query.orderBy(Alias.$(table.getState()).asc()); } else { query.orderBy(Alias.$(table.getState()).desc()); diff --git a/pom.xml b/pom.xml index a518f06f9..c751f3e9c 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 1.7 UTF-8 UTF-8 - 1.3.0-SNAPSHOT + 1.3.0 81 joerg.hohwiller@capgemini.com oss From fec34244aacb4471ba5ace741d129a2f828efc96 Mon Sep 17 00:00:00 2001 From: Rose Date: Sun, 13 Mar 2016 12:48:46 +0100 Subject: [PATCH 13/18] upgrade to oasp2.0.0 (Spring boot) --- {oasp4j-bom => bom}/pom.xml | 32 +- oasp4j-modules/oasp4j-beanmapping/.checkstyle | 7 - oasp4j-modules/oasp4j-beanmapping/pom.xml | 45 -- .../beanmapping/common/api/BeanMapper.java | 94 --- .../common/base/AbstractBeanMapper.java | 72 --- .../common/impl/DozerBeanMapper.java | 25 - .../common/impl/IdentityConverter.java | 30 - .../impl/dozer/BeanMapperImplDozer.java | 48 -- .../common/impl/dozer/IdentityConverter.java | 26 - .../impl/orika/BeanMapperImplOrika.java | 45 -- .../common/impl/orika/CustomMapperEto.java | 72 --- .../common/impl/AbstractBeanMapperTest.java | 122 ---- .../common/impl/BeanMapperImplDozerTest.java | 44 -- .../common/impl/BeanMapperImplOrikaTest.java | 42 -- .../config/app/common/dozer-mapping.xml | 18 - .../oasp4j-configuration/.checkstyle | 7 - oasp4j-modules/oasp4j-configuration/pom.xml | 25 - .../ApplicationConfigurationConstants.java | 41 -- oasp4j-modules/oasp4j-jpa-envers/pom.xml | 34 - .../api/AdvancedRevisionEntity.java | 126 ---- .../api/AdvancedRevisionListener.java | 32 - .../dataaccess/api/GenericRevisionedDao.java | 82 --- .../jpa/dataaccess/api/RevisionMetadata.java | 37 -- .../jpa/dataaccess/api/RevisionedDao.java | 13 - .../api/RevisionedMasterDataDao.java | 28 - .../base/AbstractGenericRevisionedDao.java | 94 --- .../base/AbstractRevisionedDao.java | 15 - .../dataaccess/impl/LazyRevisionMetadata.java | 71 --- oasp4j-modules/oasp4j-jpa/pom.xml | 64 -- .../module/jpa/common/api/to/OrderBy.java | 32 - .../module/jpa/common/api/to/OrderByTo.java | 64 -- .../jpa/common/api/to/PaginatedListTo.java | 56 -- .../jpa/common/api/to/PaginationResultTo.java | 90 --- .../jpa/common/api/to/PaginationTo.java | 82 --- .../jpa/common/api/to/SearchCriteriaTo.java | 114 ---- .../api/AbstractPersistenceEntity.java | 139 ----- .../oasp/module/jpa/dataaccess/api/Dao.java | 18 - .../module/jpa/dataaccess/api/GenericDao.java | 123 ---- .../jpa/dataaccess/api/MasterDataDao.java | 28 - .../api/MutablePersistenceEntity.java | 30 - .../jpa/dataaccess/base/AbstractDao.java | 26 - .../dataaccess/base/AbstractGenericDao.java | 363 ----------- .../base/AbstractMasterDataDao.java | 34 - .../base/AbstractGenericDaoTest.java | 89 --- .../module/jpa/dataaccess/base/TestDao.java | 12 - .../jpa/dataaccess/base/TestDaoImpl.java | 19 - .../jpa/dataaccess/base/TestEntity.java | 17 - .../config/app/application-default.properties | 13 - .../config/app/common/beans-common.xml | 20 - .../app/dataaccess/beans-dataaccess.xml | 15 - .../config/app/dataaccess/beans-db-plain.xml | 16 - .../config/app/dataaccess/beans-jpa.xml | 48 -- oasp4j-modules/oasp4j-logging/.checkstyle | 7 - oasp4j-modules/oasp4j-logging/pom.xml | 52 -- .../common/api/DiagnosticContextFacade.java | 33 - .../logging/common/api/LoggingConstants.java | 27 - .../impl/DiagnosticContextFacadeImpl.java | 41 -- .../common/impl/DiagnosticContextFilter.java | 156 ----- .../common/impl/SingleLinePatternLayout.java | 91 --- oasp4j-modules/oasp4j-rest/pom.xml | 78 --- .../rest/service/api/RequestParameters.java | 213 ------- .../impl/RestServiceExceptionFacade.java | 451 -------------- .../impl/json/AbstractJsonDeserializer.java | 73 --- .../impl/json/MixInAnnotationsModule.java | 48 -- .../impl/json/ObjectMapperFactory.java | 143 ----- .../impl/RestServiceExceptionFacadeTest.java | 336 ---------- oasp4j-modules/oasp4j-security/.checkstyle | 7 - oasp4j-modules/oasp4j-security/pom.xml | 74 --- .../api/accesscontrol/AccessControl.java | 104 ---- .../api/accesscontrol/AccessControlGroup.java | 161 ----- .../AccessControlPermission.java | 46 -- .../accesscontrol/AccessControlProvider.java | 55 -- .../accesscontrol/AccessControlSchema.java | 81 --- .../PrincipalAccessControlProvider.java | 22 - .../InvalidConfigurationException.java | 36 -- ...essControlBasedAuthenticationProvider.java | 159 ----- .../AbstractAccessControlProvider.java | 197 ------ .../AccessControlGrantedAuthority.java | 53 -- .../AccessControlSchemaMapper.java | 34 - .../AccessControlSchemaProvider.java | 19 - .../PrincipalGroupProviderGroupImpl.java | 55 -- ...essControlBasedAuthenticationProvider.java | 39 -- .../AccessControlProviderImpl.java | 55 -- .../AccessControlSchemaProviderImpl.java | 108 ---- .../AccessControlSchemaXmlMapper.java | 153 ----- .../AccessControlSchemaXsdWriter.java | 32 - ...SuccessHandlerSendingOkHttpStatusCode.java | 40 -- ...nUsernamePasswordAuthenticationFilter.java | 218 ------- ...ccessHandlerReturningOkHttpStatusCode.java | 31 - .../common/impl/web/RetainAnchorFilter.java | 190 ------ .../module/security/access-control-schema.xsd | 53 -- .../AccessControlSchemaTest.java | 247 -------- .../app/security/access-control-schema.xml | 45 -- .../access-control-schema_corrupted.xml | 20 - .../security/access-control-schema_cyclic.xml | 29 - .../access-control-schema_groupTypes.xml | 24 - .../access-control-schema_illegal.xml | 8 - oasp4j-modules/oasp4j-test/pom.xml | 53 -- .../api/category/CategoryComponentTest.java | 11 - .../api/category/CategoryModuleTest.java | 11 - .../api/category/CategorySubsystemTest.java | 11 - .../api/category/CategorySystemTest.java | 11 - .../test/common/base/ComponentTest.java | 27 - .../module/test/common/base/ModuleTest.java | 20 - .../test/common/base/SubsystemTest.java | 28 - .../module/test/common/base/SystemTest.java | 23 - .../src/main/resources/logback.xml | 34 - oasp4j-modules/oasp4j-web/pom.xml | 39 -- ...rtiesWebApplicationContextInitializer.java | 57 -- .../web/common/base/ToggleFilterWrapper.java | 114 ---- oasp4j-modules/pom.xml | 94 --- .../general/common/api/to/AbstractCto.java | 22 - .../general/common/api/to/AbstractEto.java | 23 - .../general/common/api/to/AbstractTo.java | 24 - .../logic/api/Offermanagement.java | 15 - .../logic/api/to/MenuItemEto.java | 85 --- .../logic/api/usecase/UcFindOffer.java | 58 -- .../logic/api/usecase/UcManageOffer.java | 28 - .../logic/api/usecase/UcManageProduct.java | 58 -- .../logic/base/usecase/AbstractOfferUc.java | 37 -- .../logic/base/usecase/AbstractProductUc.java | 109 ---- .../logic/impl/OffermanagementImpl.java | 254 -------- .../logic/impl/usecase/UcFindOfferImpl.java | 119 ---- .../logic/impl/usecase/UcFindProductImpl.java | 183 ------ .../logic/impl/usecase/UcManageOfferImpl.java | 52 -- .../impl/usecase/UcManageProductImpl.java | 174 ------ .../config/app/application-default.properties | 40 -- .../config/app/beans-application.xml | 11 - .../config/app/common/beans-common.xml | 31 - .../config/app/common/beans-dozer.xml | 18 - .../config/app/dataaccess/NamedQueries.xml | 26 - .../app/dataaccess/beans-dataaccess.xml | 16 - .../config/app/dataaccess/beans-db-plain.xml | 17 - .../config/app/dataaccess/beans-db-server.xml | 29 - .../config/app/dataaccess/beans-jpa.xml | 56 -- .../config/app/logic/beans-logic.xml | 13 - .../app/security/beans-security-filters.xml | 145 ----- .../config/app/security/beans-security.xml | 112 ---- .../config/app/service/beans-monitoring.xml | 41 -- .../config/app/service/beans-service.xml | 43 -- .../config/env/application.properties | 24 - .../db/migration/V0001__Create_schema.sql | 100 --- .../V0002_1__Delete_and_add_test_data.sql | 16 - .../db/test-data/V0003_1__Delete_data.sql | 1 - .../common/AbstractSpringIntegrationTest.java | 53 -- .../logic/impl/SalesManagementTest.java | 40 -- .../app/service/beans-test-service-rest.xml | 43 -- .../config/env/application.properties | 19 - .../oasp4j-sample-server-integration/pom.xml | 130 ---- .../restaurant/test/config/RestUrls.java | 508 --------------- .../restaurant/test/config/TestData.java | 584 ------------------ .../test/general/AppProperties.java | 86 --- .../test/general/webclient/ResponseData.java | 82 --- .../general/webclient/WebClientWrapper.java | 289 --------- .../src/main/resources/config.properties | 3 - .../java/io/oasp/AbstractDBRollbackTest.java | 62 -- .../common/AbstractRestServiceTest.java | 80 --- .../restaurant/general/common/P.java | 11 - .../common/SecurityRestServiceTest.java | 32 - .../OffermanagementRestServiceTest.java | 340 ---------- .../SalesManagementRestServiceTest.java | 344 ----------- .../StaffManagementRestServiceTest.java | 77 --- .../common/builders/TableEntityBuilder.java | 124 ---- .../common/builders/TableEtoBuilder.java | 80 --- .../TableManagementRestServiceTest.java | 246 -------- .../app/dataaccess/beans-db-connector.xml | 25 - .../config/env/application.properties | 24 - .../resources/config/tomcat/tomcat-users.xml | 11 - .../src/test/resources/initializeTests.sql | 16 - .../testdataexport.sql | 57 -- oasp4j-samples/oasp4j-sample-server/pom.xml | 63 -- .../src/main/resources/logback.xml | 102 --- .../src/main/webapp/WEB-INF/web.xml | 130 ---- .../db/migration/V0001__Create_schema.sql | 11 - pom.xml | 76 ++- samples/batch/billExport.bat | 9 + samples/batch/pom.xml | 75 +++ samples/batch/productImport.bat | 9 + samples/batch/readme.txt | 13 + samples/batch/runbatch.bat | 2 + samples/batch/src/test/resources/drinks.csv | 3 + samples/batch/src/test/resources/meals.csv | 4 + .../core}/pom.xml | 81 ++- .../gastronomy/restaurant/SpringBootApp.java | 26 + .../general/common/api/ApplicationEntity.java | 0 .../general/common/api/BinaryObject.java | 0 .../general/common/api/MoneyHelper.java | 0 .../common/api/NlsBundleApplicationRoot.java | 0 .../general/common/api/UserProfile.java | 0 .../general/common/api/Usermanagement.java | 0 .../common/api/constants/NamedQueries.java | 3 + .../api/constants/PermissionConstants.java | 0 .../general/common/api/datatype/Money.java | 2 +- .../general/common/api/datatype/Role.java | 0 .../datatype/validation/NotNegativeMoney.java | 0 .../validation/NotNegativeMoneyValidator.java | 7 +- .../ApplicationBusinessException.java | 0 .../api/exception/ApplicationException.java | 0 .../ApplicationTechnicalException.java | 0 .../IllegalEntityStateException.java | 0 .../IllegalPropertyChangeException.java | 0 .../api/exception/NoActiveUserException.java | 0 .../general/common/api/security/UserData.java | 0 .../common/api/to/UserDetailsClientTo.java | 1 + .../base/AbstractBeanMapperSupport.java | 0 .../ApplicationAuthenticationProvider.java | 23 +- .../impl/security/CsrfRequestMatcher.java | 56 ++ .../PrincipalAccessControlProviderImpl.java | 6 +- .../configuration/BeansBatchConfig.java | 217 +++++++ .../BeansDozerConfiguration.java | 31 + .../DefaultRolesPrefixPostProcessor.java | 61 ++ .../configuration/ServiceConfiguration.java | 127 ++++ .../configuration/ServletInitializer.java | 23 + .../general/configuration/WebConfig.java | 87 +++ .../configuration/WebSecurityConfig.java | 193 ++++++ .../api/ApplicationPersistenceEntity.java | 0 .../dataaccess/api/BinaryObjectEntity.java | 4 +- .../dataaccess/api/dao/ApplicationDao.java | 0 .../api/dao/ApplicationRevisionedDao.java | 0 .../dataaccess/api/dao/BinaryObjectDao.java | 0 .../dataaccess/base/DatabaseMigrator.java | 13 + .../base/MoneyAttributeConverter.java | 0 .../base/dao/ApplicationDaoImpl.java | 0 .../dao/ApplicationMasterDataDaoImpl.java | 0 .../base/dao/BinaryObjectDaoImpl.java | 0 .../general/gui/api/LoginController.java | 2 +- .../restaurant/general/logic/api/UseCase.java | 0 .../general/logic/api/to/BinaryObjectEto.java | 4 +- .../logic/base/AbstractComponentFacade.java | 1 - .../general/logic/base/AbstractUc.java | 0 .../logic/base/UcManageBinaryObject.java | 0 .../logic/impl/UcManageBinaryObjectImpl.java | 2 - .../rest/ApplicationAccessDeniedHandler.java | 0 .../rest/ApplicationObjectMapperFactory.java | 0 .../impl/rest/MoneyJsonDeserializer.java | 0 .../impl/rest/MoneyJsonSerializer.java | 0 .../impl/rest/SecurityRestServiceImpl.java | 0 .../productimport/writer/ProductWriter.java | 48 ++ .../offermanagement/common/api/Drink.java | 0 .../offermanagement/common/api/Meal.java | 0 .../offermanagement/common/api/MenuItem.java | 0 .../offermanagement/common/api/Offer.java | 8 +- .../offermanagement/common/api/Product.java | 0 .../offermanagement/common/api/SideDish.java | 0 .../common/api/datatype/DayOfWeek.java | 0 .../api/datatype/OfferSortByHitEntry.java | 0 .../common/api/datatype/OfferState.java | 0 .../api/datatype/ProductSortByHitEntry.java | 0 .../common/api/datatype/ProductType.java | 0 .../api/exception/OfferEmptyException.java | 0 .../dataaccess/api/DrinkEntity.java | 4 +- .../dataaccess/api/MealEntity.java | 2 +- .../dataaccess/api/MenuItemEntity.java | 0 .../dataaccess/api/OfferEntity.java | 4 +- .../dataaccess/api/ProductEntity.java | 4 +- .../dataaccess/api/SideDishEntity.java | 2 +- .../dataaccess/api/SpecialEntity.java | 222 +++---- .../api/WeeklyPeriodEmbeddable.java | 220 +++---- .../dataaccess/api/dao/DrinkDao.java | 0 .../dataaccess/api/dao/MealDao.java | 0 .../dataaccess/api/dao/OfferDao.java | 0 .../dataaccess/api/dao/ProductDao.java | 0 .../dataaccess/api/dao/SideDishDao.java | 0 .../dataaccess/impl/dao/DrinkDaoImpl.java | 0 .../dataaccess/impl/dao/MealDaoImpl.java | 0 .../dataaccess/impl/dao/OfferDaoImpl.java | 0 .../dataaccess/impl/dao/ProductDaoImpl.java | 2 - .../dataaccess/impl/dao/SideDishDaoImpl.java | 0 .../logic/api/Offermanagement.java | 113 +++- .../logic/api/to/DrinkEto.java | 115 ++-- .../offermanagement/logic/api/to/MealEto.java | 2 +- .../logic/api/to/MenuItemEto.java | 50 ++ .../logic/api/to/OfferCto.java | 2 +- .../logic/api/to/OfferEto.java | 269 ++++---- .../logic/api/to/OfferFilter.java | 317 +++++----- .../logic/api/to/OfferSearchCriteriaTo.java | 0 .../logic/api/to/OfferSortBy.java | 0 .../logic/api/to/ProductEto.java | 2 +- .../logic/api/to/ProductFilter.java | 252 ++++---- .../logic/api/to/ProductSearchCriteriaTo.java | 259 ++++---- .../logic/api/to/ProductSortBy.java | 128 ++-- .../logic/api/to/SideDishEto.java | 2 +- .../logic/impl/OffermanagementImpl.java | 503 +++++++++++++++ .../rest/OffermanagementRestServiceImpl.java | 40 +- .../billexport/processor/BillProcessor.java | 37 ++ .../writer/BillCompositeWriter.java | 131 ++++ .../salesmanagement/common/api/Bill.java | 2 + .../salesmanagement/common/api/Order.java | 4 + .../common/api/OrderPosition.java | 20 + .../common/api/datatype/CreditCardType.java | 0 .../api/datatype/OrderPositionState.java | 0 .../common/api/datatype/OrderState.java | 0 .../common/api/datatype/PaymentStatus.java | 0 .../api/datatype/ProductOrderState.java | 55 ++ ...TableIllegalStateCombinationException.java | 0 .../dataaccess/api/BillEntity.java | 15 +- .../dataaccess/api/OrderEntity.java | 2 +- .../dataaccess/api/OrderPositionEntity.java | 28 +- .../dataaccess/api/dao/BillDao.java | 0 .../dataaccess/api/dao/OrderDao.java | 0 .../dataaccess/api/dao/OrderPositionDao.java | 0 .../dataaccess/impl/dao/BillDaoImpl.java | 0 .../dataaccess/impl/dao/OrderDaoImpl.java | 0 .../impl/dao/OrderPositionDaoImpl.java | 5 + .../logic/api/Salesmanagement.java | 0 .../logic/api/to/BankPaymentData.java | 0 .../salesmanagement/logic/api/to/BillCto.java | 163 ++--- .../salesmanagement/logic/api/to/BillEto.java | 205 +++--- .../logic/api/to/CreditCardPaymentData.java | 0 .../logic/api/to/OrderCto.java | 36 +- .../logic/api/to/OrderEto.java | 145 ++--- .../logic/api/to/OrderPositionEto.java | 339 +++++----- .../api/to/OrderPositionSearchCriteriaTo.java | 33 +- .../logic/api/to/OrderSearchCriteriaTo.java | 0 .../logic/api/to/PaymentData.java | 0 .../logic/api/usecase/UcChangeTable.java | 0 .../logic/api/usecase/UcFindBill.java | 2 +- .../logic/api/usecase/UcFindOrder.java | 8 +- .../api/usecase/UcFindOrderPosition.java | 10 +- .../logic/api/usecase/UcManageBill.java | 2 +- .../logic/api/usecase/UcManageOrder.java | 19 +- .../api/usecase/UcManageOrderPosition.java | 4 +- .../logic/base/usecase/AbstractBillUc.java | 0 .../base/usecase/AbstractOrderPositionUc.java | 0 .../logic/base/usecase/AbstractOrderUc.java | 0 .../logic/impl/SalesmanagementImpl.java | 25 +- .../impl/paymentadapter/PaymentAdapter.java | 0 .../PaymentTransactionData.java | 0 .../impl/PaymentAdapterImpl.java | 0 .../logic/impl/usecase/UcChangeTableImpl.java | 0 .../logic/impl/usecase/UcFindBillImpl.java | 2 +- .../logic/impl/usecase/UcFindOrderImpl.java | 4 +- .../impl/usecase/UcFindOrderPositionImpl.java | 6 +- .../logic/impl/usecase/UcManageBillImpl.java | 6 +- .../logic/impl/usecase/UcManageOrderImpl.java | 133 ++-- .../usecase/UcManageOrderPositionImpl.java | 108 +++- .../rest/SalesmanagementRestServiceImpl.java | 74 +-- .../OrderPositionWebSocketController.java | 0 .../websocket/PositionStatusChangeTo.java | 7 + .../websocket/config/WebSocketConfig.java | 2 +- .../common/api/StaffMember.java | 0 .../dataaccess/api/StaffMemberEntity.java | 4 +- .../dataaccess/api/dao/StaffMemberDao.java | 0 .../impl/dao/StaffMemberDaoImpl.java | 0 .../logic/api/Staffmanagement.java | 0 .../logic/api/to/StaffMemberEto.java | 2 +- .../api/to/StaffMemberSearchCriteriaTo.java | 0 .../logic/impl/StaffmanagementImpl.java | 2 + .../rest/StaffmanagementRestServiceImpl.java | 23 +- .../tablemanagement/common/api/Table.java | 0 .../common/api/datatype/TableState.java | 0 .../dataaccess/api/TableEntity.java | 2 +- .../dataaccess/api/dao/TableDao.java | 0 .../dataaccess/impl/dao/TableDaoImpl.java | 2 +- .../logic/api/Tablemanagement.java | 0 .../logic/api/to/TableEto.java | 175 ++---- .../logic/api/to/TableSearchCriteriaTo.java | 0 .../logic/impl/TablemanagementImpl.java | 10 +- .../api/ws/v1_0/TablemanagmentWebService.java | 0 .../rest/TablemanagementRestServiceImpl.java | 11 +- .../v1_0/TablemanagementWebServiceImpl.java | 0 .../META-INF/cxf/org.apache.cxf.Logger | 0 .../core/src/main/resources/META-INF/orm.xml | 29 + .../src/main/resources/application.properties | 20 + .../config/app/batch/beans-billexport.xml | 59 ++ .../config/app/batch/beans-productimport.xml | 58 ++ .../config/app/common/dozer-mapping.xml | 4 +- .../config/app/gui/dispatcher-servlet.xml | 0 .../app/security/access-control-schema.xml | 0 .../app/websocket/websocket-context.xml | 18 +- .../config/application-h2file.properties | 8 + .../config/application-h2mem.properties | 8 + .../resources/config/application.properties | 22 + .../db/migration/V0002__R001_Master_data.sql | 20 +- .../V0003__R001_Add_blob_table_and_data.sql | 14 +- .../V0004__R001_Add_batch_tables.sql | 81 +++ .../h2/V0001__R001_Create_schema.sql | 132 ++++ .../core/src/main/resources/static/index.html | 20 + .../AbstractSpringBatchIntegrationTest.java | 95 +++ .../AccessControlSchemaXmlValidationTest.java | 114 ++-- .../general/common/MoneyHelperTest.java | 146 ++--- .../general/common/PermissionCheckTest.java | 134 ++-- .../restaurant/general/common/TestUtil.java | 32 + .../configuration/BeansJpaConfiguration.java | 68 ++ .../productimport/ProductImportJobTest.java | 91 +++ .../impl/billexport/BillExportJobTest.java | 100 +++ .../dataaccess/impl/dao/BillDaoTest.java | 34 +- .../dataaccess/impl/dao/DrinkDaoTest.java | 253 ++++---- .../logic/impl/SalesManagementTest.java | 99 +++ .../setup/db/V9001_1__Delete_data.sql | 13 + .../BillExportJobTest/expected/bills.csv | 10 + .../setup/db/V9901_1__Import_data.sql | 46 ++ .../ProductImportJobTest/data/drinks.csv | 3 + .../ProductImportJobTest/data/meals.csv | 4 + .../resources/config/application.properties | 11 + {oasp4j-samples => samples}/pom.xml | 17 +- samples/server/pom.xml | 142 +++++ samples/server/src/main/resources/logback.xml | 23 + .../src/main/webapp/META-INF/context.xml | 0 .../src/main/webapp/WEB-INF/gui/login.jsp | 0 .../server/src/main/webapp/WEB-INF/web.xml | 5 + .../server}/src/main/webapp/index.jsp | 0 src/main/javadoc/stylesheet.css | 478 -------------- src/site/resources/favicon.ico | Bin 1150 -> 0 bytes src/site/site.xml | 31 - src/site/xdoc/index.xml | 13 - {oasp4j-templates => templates}/pom.xml | 2 +- .../server}/build.xml | 102 +-- .../server}/pom.xml | 106 ++-- .../META-INF/maven/archetype-metadata.xml | 44 +- .../__earProjectName__/pom.xml | 0 .../logic/impl/UsermanagementDummyImpl.java | 0 .../config/app/dataaccess/NamedQueries.xml | 0 .../db/migration/V0002__R001_Master_data.sql | 47 ++ .../V0003__R001_Add_blob_table_and_data.sql | 2 + .../V0004__R001_Add_batch_tables.sql | 81 +++ .../h2/V0001__R001_Create_schema.sql | 132 ++++ .../server}/src/main/webapp/index.jsp | 0 .../server}/src/main/resources/pom.xml | 4 +- .../projects/basic/archetype.properties | 0 .../test/resources/projects/basic/goal.txt | 0 .../projects/enterprise/archetype.properties | 0 .../resources/projects/enterprise/goal.txt | 0 wiki | 1 - 424 files changed, 5617 insertions(+), 16121 deletions(-) rename {oasp4j-bom => bom}/pom.xml (94%) delete mode 100644 oasp4j-modules/oasp4j-beanmapping/.checkstyle delete mode 100644 oasp4j-modules/oasp4j-beanmapping/pom.xml delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/api/BeanMapper.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/base/AbstractBeanMapper.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/DozerBeanMapper.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/IdentityConverter.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/BeanMapperImplDozer.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/IdentityConverter.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/BeanMapperImplOrika.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/CustomMapperEto.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/AbstractBeanMapperTest.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplDozerTest.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplOrikaTest.java delete mode 100644 oasp4j-modules/oasp4j-beanmapping/src/test/resources/config/app/common/dozer-mapping.xml delete mode 100644 oasp4j-modules/oasp4j-configuration/.checkstyle delete mode 100644 oasp4j-modules/oasp4j-configuration/pom.xml delete mode 100644 oasp4j-modules/oasp4j-configuration/src/main/java/io/oasp/module/configuration/common/api/ApplicationConfigurationConstants.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/pom.xml delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionEntity.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionListener.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericRevisionedDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionMetadata.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedMasterDataDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericRevisionedDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractRevisionedDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/impl/LazyRevisionMetadata.java delete mode 100644 oasp4j-modules/oasp4j-jpa/pom.xml delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderBy.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderByTo.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginatedListTo.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationResultTo.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationTo.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/SearchCriteriaTo.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/AbstractPersistenceEntity.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/Dao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MasterDataDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MutablePersistenceEntity.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractMasterDataDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDaoTest.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDao.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDaoImpl.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestEntity.java delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/application-default.properties delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/common/beans-common.xml delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-dataaccess.xml delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-db-plain.xml delete mode 100644 oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-jpa.xml delete mode 100644 oasp4j-modules/oasp4j-logging/.checkstyle delete mode 100644 oasp4j-modules/oasp4j-logging/pom.xml delete mode 100644 oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/DiagnosticContextFacade.java delete mode 100644 oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/LoggingConstants.java delete mode 100644 oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFacadeImpl.java delete mode 100644 oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFilter.java delete mode 100644 oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/SingleLinePatternLayout.java delete mode 100644 oasp4j-modules/oasp4j-rest/pom.xml delete mode 100644 oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/api/RequestParameters.java delete mode 100644 oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacade.java delete mode 100644 oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java delete mode 100644 oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/MixInAnnotationsModule.java delete mode 100644 oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/ObjectMapperFactory.java delete mode 100644 oasp4j-modules/oasp4j-rest/src/test/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacadeTest.java delete mode 100644 oasp4j-modules/oasp4j-security/.checkstyle delete mode 100644 oasp4j-modules/oasp4j-security/pom.xml delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControl.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlGroup.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlPermission.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlSchema.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/PrincipalAccessControlProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/exception/InvalidConfigurationException.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlBasedAuthenticationProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlGrantedAuthority.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaMapper.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/PrincipalGroupProviderGroupImpl.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/SimpleAccessControlBasedAuthenticationProvider.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlProviderImpl.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaProviderImpl.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXmlMapper.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXsdWriter.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/AuthenticationSuccessHandlerSendingOkHttpStatusCode.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/JsonUsernamePasswordAuthenticationFilter.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/LogoutSuccessHandlerReturningOkHttpStatusCode.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/web/RetainAnchorFilter.java delete mode 100644 oasp4j-modules/oasp4j-security/src/main/resources/io/oasp/module/security/access-control-schema.xsd delete mode 100644 oasp4j-modules/oasp4j-security/src/test/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaTest.java delete mode 100644 oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema.xml delete mode 100644 oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_corrupted.xml delete mode 100644 oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_cyclic.xml delete mode 100644 oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_groupTypes.xml delete mode 100644 oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_illegal.xml delete mode 100644 oasp4j-modules/oasp4j-test/pom.xml delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryComponentTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryModuleTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySubsystemTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySystemTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ComponentTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ModuleTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SubsystemTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SystemTest.java delete mode 100644 oasp4j-modules/oasp4j-test/src/main/resources/logback.xml delete mode 100644 oasp4j-modules/oasp4j-web/pom.xml delete mode 100644 oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/PropertiesWebApplicationContextInitializer.java delete mode 100644 oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/ToggleFilterWrapper.java delete mode 100644 oasp4j-modules/pom.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractCto.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractEto.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractTo.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/application-default.properties delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/beans-application.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-common.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-dozer.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/NamedQueries.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-dataaccess.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-plain.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-server.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-jpa.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/logic/beans-logic.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security-filters.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-monitoring.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-service.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/config/env/application.properties delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0001__Create_schema.sql delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0002_1__Delete_and_add_test_data.sql delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0003_1__Delete_data.sql delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringIntegrationTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/test/resources/config/app/service/beans-test-service-rest.xml delete mode 100644 oasp4j-samples/oasp4j-sample-core/src/test/resources/config/env/application.properties delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/pom.xml delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/TestData.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/AppProperties.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/ResponseData.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/WebClientWrapper.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/main/resources/config.properties delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/AbstractDBRollbackTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/P.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/SecurityRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/services/SalesManagementRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/staffmanagement/services/StaffManagementRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEntityBuilder.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEtoBuilder.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/services/TableManagementRestServiceTest.java delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/app/dataaccess/beans-db-connector.xml delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/env/application.properties delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/tomcat/tomcat-users.xml delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/initializeTests.sql delete mode 100644 oasp4j-samples/oasp4j-sample-server-integration/testdataexport.sql delete mode 100644 oasp4j-samples/oasp4j-sample-server/pom.xml delete mode 100644 oasp4j-samples/oasp4j-sample-server/src/main/resources/logback.xml delete mode 100644 oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/web.xml delete mode 100644 oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/db/migration/V0001__Create_schema.sql create mode 100644 samples/batch/billExport.bat create mode 100644 samples/batch/pom.xml create mode 100644 samples/batch/productImport.bat create mode 100644 samples/batch/readme.txt create mode 100644 samples/batch/runbatch.bat create mode 100644 samples/batch/src/test/resources/drinks.csv create mode 100644 samples/batch/src/test/resources/meals.csv rename {oasp4j-samples/oasp4j-sample-core => samples/core}/pom.xml (74%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/SpringBootApp.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/ApplicationEntity.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/BinaryObject.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/MoneyHelper.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/NlsBundleApplicationRoot.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/UserProfile.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/Usermanagement.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java (89%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/PermissionConstants.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Role.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoney.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java (93%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationBusinessException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationTechnicalException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalEntityStateException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalPropertyChangeException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/NoActiveUserException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/security/UserData.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/base/AbstractBeanMapperSupport.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java (81%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/CsrfRequestMatcher.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java (100%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansBatchConfig.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansDozerConfiguration.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/DefaultRolesPrefixPostProcessor.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServiceConfiguration.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServletInitializer.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebConfig.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebSecurityConfig.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/ApplicationPersistenceEntity.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationRevisionedDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/BinaryObjectDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java (86%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/MoneyAttributeConverter.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationMasterDataDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/BinaryObjectDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java (97%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/UseCase.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java (80%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java (99%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractUc.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/UcManageBinaryObject.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationAccessDeniedHandler.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationObjectMapperFactory.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonDeserializer.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonSerializer.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/SecurityRestServiceImpl.java (100%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/writer/ProductWriter.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Drink.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Meal.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/MenuItem.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Product.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/SideDish.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferSortByHitEntry.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferState.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductSortByHitEntry.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductType.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/exception/OfferEmptyException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MenuItemEntity.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java (97%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/DrinkDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/MealDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/OfferDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/ProductDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/SideDishDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/DrinkDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/MealDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java (99%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/SideDishDaoImpl.java (100%) rename oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java => samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java (54%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java (57%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java (79%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java (53%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java (91%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSearchCriteriaTo.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java (85%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java (72%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java (81%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java (79%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java (89%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/processor/BillProcessor.java create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/writer/BillCompositeWriter.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java (89%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java (85%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/CreditCardType.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderPositionState.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderState.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/PaymentStatus.java (100%) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/ProductOrderState.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/exception/ChangeTableIllegalStateCombinationException.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java (92%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java (85%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/BillDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderPositionDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java (93%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/Salesmanagement.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BankPaymentData.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java (56%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java (53%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/CreditCardPaymentData.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java (57%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java (53%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java (57%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java (70%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderSearchCriteriaTo.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/PaymentData.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcChangeTable.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java (92%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java (86%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java (74%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java (91%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractBillUc.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderPositionUc.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderUc.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java (92%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentAdapter.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentTransactionData.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/impl/PaymentAdapterImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcChangeTableImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java (97%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java (99%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java (57%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java (61%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java (83%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/OrderPositionWebSocketController.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java (87%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java (93%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/common/api/StaffMember.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/dao/StaffMemberDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/impl/dao/StaffMemberDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/Staffmanagement.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberSearchCriteriaTo.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java (80%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/Table.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java (98%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/dao/TableDao.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/Tablemanagement.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java (54%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableSearchCriteriaTo.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java (95%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/api/ws/v1_0/TablemanagmentWebService.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java (94%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/ws/v1_0/TablemanagementWebServiceImpl.java (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/resources/META-INF/cxf/org.apache.cxf.Logger (100%) create mode 100644 samples/core/src/main/resources/META-INF/orm.xml create mode 100644 samples/core/src/main/resources/application.properties create mode 100644 samples/core/src/main/resources/config/app/batch/beans-billexport.xml create mode 100644 samples/core/src/main/resources/config/app/batch/beans-productimport.xml rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/resources/config/app/common/dozer-mapping.xml (96%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/resources/config/app/gui/dispatcher-servlet.xml (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/resources/config/app/security/access-control-schema.xml (100%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/main/resources/config/app/websocket/websocket-context.xml (96%) create mode 100644 samples/core/src/main/resources/config/application-h2file.properties create mode 100644 samples/core/src/main/resources/config/application-h2mem.properties create mode 100644 samples/core/src/main/resources/config/application.properties rename oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0002__Master_data.sql => samples/core/src/main/resources/db/migration/V0002__R001_Master_data.sql (67%) rename oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0003__Add_blob_table_and_data.sql => samples/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql (99%) create mode 100644 samples/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql create mode 100644 samples/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql create mode 100644 samples/core/src/main/resources/static/index.html create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringBatchIntegrationTest.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java (91%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java (80%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java (71%) create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/TestUtil.java create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/configuration/BeansJpaConfiguration.java create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/ProductImportJobTest.java create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/BillExportJobTest.java rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java (51%) rename {oasp4j-samples/oasp4j-sample-core => samples/core}/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java (72%) create mode 100644 samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java create mode 100644 samples/core/src/test/resources/AllTests/setup/db/V9001_1__Delete_data.sql create mode 100644 samples/core/src/test/resources/BillExportJobTest/expected/bills.csv create mode 100644 samples/core/src/test/resources/BillExportJobTest/setup/db/V9901_1__Import_data.sql create mode 100644 samples/core/src/test/resources/ProductImportJobTest/data/drinks.csv create mode 100644 samples/core/src/test/resources/ProductImportJobTest/data/meals.csv create mode 100644 samples/core/src/test/resources/config/application.properties rename {oasp4j-samples => samples}/pom.xml (86%) create mode 100644 samples/server/pom.xml create mode 100644 samples/server/src/main/resources/logback.xml rename {oasp4j-samples/oasp4j-sample-server => samples/server}/src/main/webapp/META-INF/context.xml (100%) rename {oasp4j-samples/oasp4j-sample-server => samples/server}/src/main/webapp/WEB-INF/gui/login.jsp (100%) create mode 100644 samples/server/src/main/webapp/WEB-INF/web.xml rename {oasp4j-samples/oasp4j-sample-server => samples/server}/src/main/webapp/index.jsp (100%) delete mode 100644 src/main/javadoc/stylesheet.css delete mode 100644 src/site/resources/favicon.ico delete mode 100644 src/site/site.xml delete mode 100644 src/site/xdoc/index.xml rename {oasp4j-templates => templates}/pom.xml (94%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/build.xml (65%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/pom.xml (56%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/main/resources/META-INF/maven/archetype-metadata.xml (70%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/main/resources/archetype-resources/__earProjectName__/pom.xml (100%) rename {oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core => templates/server/src/main/resources/archetype-resources/core}/src/main/java/general/logic/impl/UsermanagementDummyImpl.java (100%) rename {oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core => templates/server/src/main/resources/archetype-resources/core}/src/main/resources/config/app/dataaccess/NamedQueries.xml (100%) create mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql create mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql create mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql create mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql rename {oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-server => templates/server/src/main/resources/archetype-resources/server}/src/main/webapp/index.jsp (100%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/main/resources/pom.xml (98%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/test/resources/projects/basic/archetype.properties (100%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/test/resources/projects/basic/goal.txt (100%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/test/resources/projects/enterprise/archetype.properties (100%) rename {oasp4j-templates/oasp4j-template-server => templates/server}/src/test/resources/projects/enterprise/goal.txt (100%) delete mode 160000 wiki diff --git a/oasp4j-bom/pom.xml b/bom/pom.xml similarity index 94% rename from oasp4j-bom/pom.xml rename to bom/pom.xml index cfe0503bb..b07c4b2f9 100644 --- a/oasp4j-bom/pom.xml +++ b/bom/pom.xml @@ -19,8 +19,7 @@ UTF-8 UTF-8 - 3.0.5 - 4.0.9.RELEASE + 3.1.4 joerg.hohwiller@capgemini.com bom @@ -28,12 +27,6 @@ - - - org.springframework - spring-context - ${spring.version} - javax.annotation @@ -62,7 +55,7 @@ net.sf.m-m-m mmm-util-core - 6.0.0 + 7.0.0 @@ -114,8 +107,7 @@ javax.servlet javax.servlet-api - 3.1.0 - + provided @@ -123,11 +115,11 @@ jstl 1.2 - + javax.ws.rs javax.ws.rs-api - 2.0 + 2.0.1 @@ -221,18 +213,16 @@ 1.54 - + javax.el javax.el-api 2.2.4 - test org.glassfish.web javax.el 2.2.4 - test @@ -246,6 +236,16 @@ oasp4j-logging ${project.version} + + io.oasp.java.modules + oasp4j-basic + ${project.version} + + + io.oasp.java.modules + oasp4j-batch + ${project.version} + io.oasp.java.modules oasp4j-beanmapping diff --git a/oasp4j-modules/oasp4j-beanmapping/.checkstyle b/oasp4j-modules/oasp4j-beanmapping/.checkstyle deleted file mode 100644 index b6203b021..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/oasp4j-modules/oasp4j-beanmapping/pom.xml b/oasp4j-modules/oasp4j-beanmapping/pom.xml deleted file mode 100644 index 3c245344c..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-beanmapping - ${oasp4j.version} - jar - ${project.artifactId} - Minimal shim for bean mapping to convert between compatible Java beans (e.g. JPA entity to transfer-object and vice versa). - - - - net.sf.dozer - dozer - - - javax.inject - javax.inject - - - net.sf.m-m-m - mmm-util-core - - - - - ma.glasnost.orika - orika-core - true - - - - io.oasp.java.modules - oasp4j-test - test - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/api/BeanMapper.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/api/BeanMapper.java deleted file mode 100644 index dc8657ad4..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/api/BeanMapper.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.oasp.module.beanmapping.common.api; - -import java.util.List; -import java.util.Set; - -/** - * This is the interface used to convert from one Java bean to another compatible bean (e.g. from a JPA entity to a - * corresponding transfer-object). - * - * @author hohwille - */ -public interface BeanMapper { - - /** - * Recursively converts the given source {@link Object} to the given target {@link Class}. - * - * @param is the generic type to convert to. - * @param source is the object to convert. - * @param targetClass is the {@link Class} reflecting the type to convert to. - * @return the converted object. Will be {@code null} if source is {@code null}. - */ - T map(Object source, Class targetClass); - - /** - * A type-safe variant of {@link #map(Object, Class)} to prevent accidental abuse (e.g. mapping of apples to bananas). - * - * @param is a common super-type (interface) of source and targetType. - * @param is the generic type of source. - * @param is the generic type to convert to (target). - * @param apiClass is the {@link Class} reflecting the {@literal }. - * @param source is the object to convert. - * @param targetClass is the {@link Class} reflecting the type to convert to. - * @return the converted object. Will be {@code null} if source is {@code null}. - * @since 1.3.0 - */ - T mapTypesafe(Class apiClass, S source, Class targetClass); - - /** - * Creates a new {@link List} with the {@link #map(Object, Class) mapped bean} for each {@link List#get(int) entry} of - * the given {@link List}. Uses {@code false} for suppressNullValues (see - * {@link #mapList(List, Class, boolean)}). - * - * @param is the generic type to convert the {@link List} entries to. - * @param source is the {@link List} with the source objects. - * @param targetClass is the {@link Class} reflecting the type to convert each {@link List} entry to. - * @return the {@link List} with the converted objects. Will be {@link List#isEmpty() empty} is source is - * empty or {@code null}. - */ - List mapList(List source, Class targetClass); - - /** - * Creates a new {@link List} with the {@link #map(Object, Class) mapped bean} for each {@link List#get(int) entry} of - * the given {@link List}. - * - * @param is the generic type to convert the {@link List} entries to. - * @param source is the {@link List} with the source objects. - * @param targetClass is the {@link Class} reflecting the type to convert each {@link List} entry to. - * @param suppressNullValues {@code true} if {@code null} values shall be suppressed/omitted in the - * resulting {@link List}, {@code false} otherwise. - * @return the {@link List} with the converted objects. Will be {@link List#isEmpty() empty} is source is - * empty or {@code null}. - * @since 1.3.0 - */ - List mapList(List source, Class targetClass, boolean suppressNullValues); - - /** - * Creates a new {@link Set} with the {@link #map(Object, Class) mapped bean} for each {@link Set#contains(Object) - * entry} of the given {@link Set}. Uses {@code false} for suppressNullValues (see - * {@link #mapSet(Set, Class, boolean)}). - * - * @param is the generic type to convert the {@link Set} entries to. - * @param source is the {@link Set} with the source objects. - * @param targetClass is the {@link Class} reflecting the type to convert each {@link Set} entry to. - * @return the {@link Set} with the converted objects. Will be {@link Set#isEmpty() empty} is source is - * empty or {@code null}. - */ - Set mapSet(Set source, Class targetClass); - - /** - * Creates a new {@link Set} with the {@link #map(Object, Class) mapped bean} for each {@link Set#contains(Object) - * entry} of the given {@link Set}. - * - * @param is the generic type to convert the {@link Set} entries to. - * @param source is the {@link Set} with the source objects. - * @param targetClass is the {@link Class} reflecting the type to convert each {@link Set} entry to. - * @param suppressNullValues {@code true} if {@code null} values shall be suppressed/omitted in the - * resulting {@link Set}, {@code false} otherwise. - * @return the {@link Set} with the converted objects. Will be {@link Set#isEmpty() empty} is source is - * empty or {@code null}. - * @since 1.3.0 - */ - Set mapSet(Set source, Class targetClass, boolean suppressNullValues); - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/base/AbstractBeanMapper.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/base/AbstractBeanMapper.java deleted file mode 100644 index 6f3a7307d..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/base/AbstractBeanMapper.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.oasp.module.beanmapping.common.base; - -import io.oasp.module.beanmapping.common.api.BeanMapper; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * The abstract base implementation of {@link BeanMapper}. - * - * @author hohwille - */ -public abstract class AbstractBeanMapper implements BeanMapper { - - /** - * The constructor. - */ - public AbstractBeanMapper() { - - super(); - } - - @Override - public T mapTypesafe(Class apiClass, S source, Class targetClass) { - - return map(source, targetClass); - } - - @Override - public List mapList(List source, Class targetClass) { - - return mapList(source, targetClass, false); - } - - @Override - public List mapList(List source, Class targetClass, boolean suppressNullValues) { - - if ((source == null) || (source.isEmpty())) { - return new ArrayList<>(); - } - List result = new ArrayList<>(source.size()); - for (Object sourceObject : source) { - if ((sourceObject != null) || !suppressNullValues) { - result.add(map(sourceObject, targetClass)); - } - } - return result; - } - - @Override - public Set mapSet(Set source, Class targetClass) { - - return mapSet(source, targetClass, false); - } - - @Override - public Set mapSet(Set source, Class targetClass, boolean suppressNullValues) { - - if ((source == null) || (source.isEmpty())) { - return new HashSet<>(); - } - Set result = new HashSet<>(source.size()); - for (Object sourceObject : source) { - if ((sourceObject != null) || !suppressNullValues) { - result.add(map(sourceObject, targetClass)); - } - } - return result; - } -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/DozerBeanMapper.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/DozerBeanMapper.java deleted file mode 100644 index 5a2e4c93f..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/DozerBeanMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.oasp.module.beanmapping.common.impl; - -import io.oasp.module.beanmapping.common.impl.dozer.BeanMapperImplDozer; - -import org.dozer.Mapper; - -/** - * This is the implementation of {@link io.oasp.module.beanmapping.common.api.BeanMapper} using dozer {@link Mapper}. - * - * @author hohwille - * @deprecated - use {@link BeanMapperImplDozer} instead as this class name clashes with - * {@link org.dozer.DozerBeanMapper}. - */ -@Deprecated -public class DozerBeanMapper extends BeanMapperImplDozer { - - /** - * The constructor. - */ - public DozerBeanMapper() { - - super(); - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/IdentityConverter.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/IdentityConverter.java deleted file mode 100644 index 7a83a754f..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/IdentityConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.oasp.module.beanmapping.common.impl; - -import org.dozer.CustomConverter; - -/** - * Dozer {@link CustomConverter} that returns the original source object reference (identity conversion). - * - * @author hohwille - * @deprecated - use {@link io.oasp.module.beanmapping.common.impl.dozer.IdentityConverter} - */ -@Deprecated -public class IdentityConverter implements CustomConverter { - - /** - * The constructor. - */ - public IdentityConverter() { - - super(); - System.err.println("This class is deprecated. Please use " - + io.oasp.module.beanmapping.common.impl.dozer.IdentityConverter.class.getName()); - } - - @Override - public Object convert(Object destination, Object source, Class destinationClass, Class sourceClass) { - - return source; - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/BeanMapperImplDozer.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/BeanMapperImplDozer.java deleted file mode 100644 index 283a0cb5f..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/BeanMapperImplDozer.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.oasp.module.beanmapping.common.impl.dozer; - -import io.oasp.module.beanmapping.common.base.AbstractBeanMapper; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.dozer.Mapper; - -/** - * This is the implementation of {@link io.oasp.module.beanmapping.common.api.BeanMapper} using dozer {@link Mapper}. - * - * @author hohwille - * @since 1.3.0 - */ -@Named -public class BeanMapperImplDozer extends AbstractBeanMapper { - - /** The dozer instance to use. */ - private Mapper dozer; - - /** - * The constructor. - */ - public BeanMapperImplDozer() { - - super(); - } - - /** - * @param dozer is the {@link Mapper} to {@link Inject}. - */ - @Inject - public void setDozer(Mapper dozer) { - - this.dozer = dozer; - } - - @Override - public T map(Object source, Class targetClass) { - - if (source == null) { - return null; - } - return this.dozer.map(source, targetClass); - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/IdentityConverter.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/IdentityConverter.java deleted file mode 100644 index 3946bd033..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/dozer/IdentityConverter.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.oasp.module.beanmapping.common.impl.dozer; - -import org.dozer.CustomConverter; - -/** - * Dozer {@link CustomConverter} that returns the original source object reference (identity conversion). - * - * @author hohwille - */ -public class IdentityConverter implements CustomConverter { - - /** - * The constructor. - */ - public IdentityConverter() { - - super(); - } - - @Override - public Object convert(Object destination, Object source, Class destinationClass, Class sourceClass) { - - return source; - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/BeanMapperImplOrika.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/BeanMapperImplOrika.java deleted file mode 100644 index 51547be46..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/BeanMapperImplOrika.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.oasp.module.beanmapping.common.impl.orika; - -import io.oasp.module.beanmapping.common.base.AbstractBeanMapper; - -import javax.inject.Inject; - -import ma.glasnost.orika.MapperFacade; - -/** - * This is the implementation of {@link io.oasp.module.beanmapping.common.api.BeanMapper} using orika - * {@link MapperFacade}. - * - * @author hohwille - */ -public class BeanMapperImplOrika extends AbstractBeanMapper { - - private MapperFacade orika; - - /** - * The constructor. - */ - public BeanMapperImplOrika() { - - super(); - } - - /** - * @param orika the orika to set - */ - @Inject - public void setOrika(MapperFacade orika) { - - this.orika = orika; - } - - @Override - public T map(Object source, Class targetClass) { - - if (source == null) { - return null; - } - return this.orika.map(source, targetClass); - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/CustomMapperEto.java b/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/CustomMapperEto.java deleted file mode 100644 index 5c7903962..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/main/java/io/oasp/module/beanmapping/common/impl/orika/CustomMapperEto.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.oasp.module.beanmapping.common.impl.orika; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; - -import ma.glasnost.orika.CustomMapper; -import ma.glasnost.orika.MappingContext; - -import net.sf.mmm.util.entity.api.GenericEntity; -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.pojo.descriptor.api.PojoDescriptor; -import net.sf.mmm.util.pojo.descriptor.api.PojoDescriptorBuilder; -import net.sf.mmm.util.pojo.descriptor.api.PojoDescriptorBuilderFactory; -import net.sf.mmm.util.pojo.descriptor.impl.PojoDescriptorBuilderFactoryImpl; -import net.sf.mmm.util.transferobject.api.EntityTo; - -/** - * {@link CustomMapper} to map from {@link PersistenceEntity} to {@link EntityTo} to solve - * {@link EntityTo#getModificationCounter() modification counter issue}. - * - * @author hohwille - */ -// @Named -@SuppressWarnings("rawtypes") -public class CustomMapperEto extends CustomMapper { - - private PojoDescriptorBuilder pojoDescriptorBuilder; - - private PojoDescriptorBuilderFactory pojoDescriptorBuilderFactory; - - private PojoDescriptor descriptor; - - /** - * The constructor. - */ - public CustomMapperEto() { - - super(); - } - - @Override - public void mapAtoB(GenericEntity source, EntityTo target, MappingContext context) { - - super.mapAtoB(source, target, context); - this.descriptor.setProperty(target, "persistentEntity", source); - } - - /** - * Initializes this class to be functional. - */ - @PostConstruct - public void initialize() { - - if (this.pojoDescriptorBuilderFactory == null) { - this.pojoDescriptorBuilderFactory = PojoDescriptorBuilderFactoryImpl.getInstance(); - } - if (this.pojoDescriptorBuilder == null) { - this.pojoDescriptorBuilder = this.pojoDescriptorBuilderFactory.createPrivateFieldDescriptorBuilder(); - } - this.descriptor = this.pojoDescriptorBuilder.getDescriptor(EntityTo.class); - } - - /** - * @param pojoDescriptorBuilderFactory the pojoDescriptorBuilderFactory to set - */ - @Inject - public void setPojoDescriptorBuilderFactory(PojoDescriptorBuilderFactory pojoDescriptorBuilderFactory) { - - this.pojoDescriptorBuilderFactory = pojoDescriptorBuilderFactory; - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/AbstractBeanMapperTest.java b/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/AbstractBeanMapperTest.java deleted file mode 100644 index 92f7bb549..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/AbstractBeanMapperTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.oasp.module.beanmapping.common.impl; - -import io.oasp.module.beanmapping.common.api.BeanMapper; -import io.oasp.module.test.common.base.ModuleTest; - -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.entity.api.RevisionedEntity; -import net.sf.mmm.util.entity.base.AbstractRevisionedEntity; -import net.sf.mmm.util.transferobject.api.EntityTo; - -import org.junit.Test; - -/** - * The abstract test-case for testing {@link BeanMapper} via its interface. - * - * @author hohwille - */ -public abstract class AbstractBeanMapperTest extends ModuleTest { - - /** - * @return the {@link BeanMapper} instance to test. - */ - protected abstract BeanMapper getBeanMapper(); - - /** - * Tests {@link BeanMapper#mapTypesafe(Class, Object, Class)} for an {@link PersistenceEntity entity} to an - * {@link EntityTo ETO} and ensures that if the {@link PersistenceEntity#getModificationCounter() modification - * counter} gets updated after conversion that the {@link EntityTo ETO} reflects this change. - */ - @Test - public void testMapEntity2Eto() { - - // given - BeanMapper mapper = getBeanMapper(); - MyBeanEntity entity = new MyBeanEntity(); - Long id = 1L; - entity.setId(id); - int version = 1; - entity.setModificationCounter(version); - Number revision = 10L; - entity.setRevision(revision); - String property = "its magic"; - entity.setProperty(property); - - // when - MyBeanEto eto = mapper.mapTypesafe(MyBean.class, entity, MyBeanEto.class); - - // then - assertThat(eto).isNotNull(); - assertThat(eto.getId()).isEqualTo(id); - assertThat(eto.getModificationCounter()).isEqualTo(version); - assertThat(eto.getRevision()).isEqualTo(revision); - assertThat(eto.getProperty()).isEqualTo(property); - // sepcial feature: update of modificationCounter is performed when TX is closed what is typically after conversion - int newVersion = version + 1; - entity.setModificationCounter(newVersion); - assertThat(eto.getModificationCounter()).isEqualTo(newVersion); - } - - /** - * Interface for {@link MyBeanEntity} and {@link MyBeanEto}. - */ - public static interface MyBean extends RevisionedEntity { - - /** - * @return property - */ - String getProperty(); - - /** - * @param property the property to set - */ - void setProperty(String property); - - } - - /** - * {@link PersistenceEntity} for testing. - */ - public static class MyBeanEntity extends AbstractRevisionedEntity implements PersistenceEntity, MyBean { - - private static final long serialVersionUID = 1L; - - private String property; - - @Override - public String getProperty() { - - return this.property; - } - - @Override - public void setProperty(String property) { - - this.property = property; - } - - } - - /** - * {@link EntityTo ETO} for testing. - */ - public static class MyBeanEto extends EntityTo implements MyBean { - - private static final long serialVersionUID = 1L; - - private String property; - - @Override - public String getProperty() { - - return this.property; - } - - @Override - public void setProperty(String property) { - - this.property = property; - } - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplDozerTest.java b/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplDozerTest.java deleted file mode 100644 index 7aec46b89..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplDozerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.oasp.module.beanmapping.common.impl; - -import io.oasp.module.beanmapping.common.api.BeanMapper; -import io.oasp.module.beanmapping.common.impl.dozer.BeanMapperImplDozer; -import io.oasp.module.beanmapping.common.impl.dozer.IdentityConverter; - -import java.util.Arrays; -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.transferobject.api.EntityTo; - -import org.dozer.DozerBeanMapper; -import org.dozer.loader.api.BeanMappingBuilder; -import org.dozer.loader.api.FieldsMappingOptions; - -/** - * Test of {@link BeanMapperImplDozer} based on {@link AbstractBeanMapperTest}. - * - * @author hohwille - */ -public class BeanMapperImplDozerTest extends AbstractBeanMapperTest { - - @Override - protected BeanMapper getBeanMapper() { - - BeanMapperImplDozer mapper = new BeanMapperImplDozer(); - List mappingFiles = Arrays.asList("config/app/common/dozer-mapping.xml"); - DozerBeanMapper dozer = new DozerBeanMapper(mappingFiles); - BeanMappingBuilder builder = new BeanMappingBuilder() { - - @Override - protected void configure() { - - mapping(PersistenceEntity.class, EntityTo.class).fields(this_(), field("persistentEntity").accessible(), - FieldsMappingOptions.customConverter(IdentityConverter.class)); - } - }; - dozer.addMapping(builder); - mapper.setDozer(dozer); - return mapper; - } - -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplOrikaTest.java b/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplOrikaTest.java deleted file mode 100644 index e6564ec77..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/test/java/io/oasp/module/beanmapping/common/impl/BeanMapperImplOrikaTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.oasp.module.beanmapping.common.impl; - -import io.oasp.module.beanmapping.common.api.BeanMapper; -import io.oasp.module.beanmapping.common.impl.orika.BeanMapperImplOrika; -import io.oasp.module.beanmapping.common.impl.orika.CustomMapperEto; -import ma.glasnost.orika.Mapper; -import ma.glasnost.orika.MapperFacade; -import ma.glasnost.orika.MapperFactory; -import ma.glasnost.orika.impl.DefaultMapperFactory; - -import net.sf.mmm.util.entity.base.AbstractRevisionedEntity; -import net.sf.mmm.util.transferobject.api.EntityTo; - -import org.junit.Ignore; - -/** - * Test of {@link BeanMapperImplOrika} based on {@link AbstractBeanMapperTest}. - * - * @author hohwille - */ -@Ignore -public class BeanMapperImplOrikaTest extends AbstractBeanMapperTest { - - @Override - protected BeanMapper getBeanMapper() { - - BeanMapperImplOrika mapper = new BeanMapperImplOrika(); - MapperFactory factory = new DefaultMapperFactory.Builder().build(); - CustomMapperEto customMapper = new CustomMapperEto(); - customMapper.initialize(); - // mapping via interface seems not to work in orika... - // factory.classMap(PersistenceEntity.class, EntityTo.class).customize(customMapper).byDefault().register(); - - // already this breaks the default mapping compared to not configuring a classMap. - // factory.classMap(AbstractRevisionedEntity.class, EntityTo.class).byDefault().register(); - factory.classMap(AbstractRevisionedEntity.class, EntityTo.class).customize((Mapper) customMapper).byDefault() - .register(); - MapperFacade orika = factory.getMapperFacade(); - mapper.setOrika(orika); - return mapper; - } -} diff --git a/oasp4j-modules/oasp4j-beanmapping/src/test/resources/config/app/common/dozer-mapping.xml b/oasp4j-modules/oasp4j-beanmapping/src/test/resources/config/app/common/dozer-mapping.xml deleted file mode 100644 index 3e71f5ebb..000000000 --- a/oasp4j-modules/oasp4j-beanmapping/src/test/resources/config/app/common/dozer-mapping.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - true - - - java.lang.String - java.lang.Long - java.lang.Integer - java.lang.Number - java.lang.Boolean - - - diff --git a/oasp4j-modules/oasp4j-configuration/.checkstyle b/oasp4j-modules/oasp4j-configuration/.checkstyle deleted file mode 100644 index b6203b021..000000000 --- a/oasp4j-modules/oasp4j-configuration/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/oasp4j-modules/oasp4j-configuration/pom.xml b/oasp4j-modules/oasp4j-configuration/pom.xml deleted file mode 100644 index 48582e42d..000000000 --- a/oasp4j-modules/oasp4j-configuration/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-configuration - ${oasp4j.version} - jar - ${project.artifactId} - Configuration Module of the Open Application Standard Platform for Java (OASP4J). - - - - io.oasp.java.modules - oasp4j-test - test - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-configuration/src/main/java/io/oasp/module/configuration/common/api/ApplicationConfigurationConstants.java b/oasp4j-modules/oasp4j-configuration/src/main/java/io/oasp/module/configuration/common/api/ApplicationConfigurationConstants.java deleted file mode 100644 index e8e3db805..000000000 --- a/oasp4j-modules/oasp4j-configuration/src/main/java/io/oasp/module/configuration/common/api/ApplicationConfigurationConstants.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.oasp.module.configuration.common.api; - -/** - * Central constants for spring configuration files. Mainly for testing but may also be used for productive usage. - * - * @author hohwille - */ -public final class ApplicationConfigurationConstants { - - /** Path to the spring XML configuration file for the entire application. */ - public static final String BEANS_APPLICATION = "classpath:/config/app/beans-application.xml"; - - /** Path to the spring XML configuration file for the service layer. */ - public static final String BEANS_SERVICE = "classpath:/config/app/service/beans-service.xml"; - - /** Path to the spring XML configuration file for the logic layer. */ - public static final String BEANS_LOGIC = "classpath:/config/app/logic/beans-logic.xml"; - - /** Path to the spring XML configuration file for the data-acccess layer. */ - public static final String BEANS_DATA_ACCESS = "classpath:/config/app/dataaccess/beans-dataaccess.xml"; - - /** - * Path to the spring XML configuration file for the common and cross-cutting code that is not assigned to any layer. - */ - public static final String BEANS_COMMON = "classpath:/config/app/common/beans-common.xml"; - - /** Path to the spring XML configuration file for the security. */ - public static final String BEANS_SECURITY = "classpath:/config/app/security/beans-security.xml"; - - /** Path to the XML configuration of the access control schema. */ - public static final String SECURITY_ACCESS_CONTROL_SCHEMA = "config/app/security/access-control-schema.xml"; - - /** - * Construction prohibited. - */ - private ApplicationConfigurationConstants() { - - super(); - } - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/pom.xml b/oasp4j-modules/oasp4j-jpa-envers/pom.xml deleted file mode 100644 index fcf4a775a..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-jpa-envers - ${oasp4j.version} - jar - ${project.artifactId} - JPA-based persistence infrastructure of the Open Application Standard Platform for Java (OASP4J). - - - - io.oasp.java.modules - oasp4j-jpa - - - org.hibernate - hibernate-envers - - - - io.oasp.java.modules - oasp4j-test - test - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionEntity.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionEntity.java deleted file mode 100644 index 04e0a9048..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionEntity.java +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.Date; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -import org.hibernate.envers.RevisionEntity; -import org.hibernate.envers.RevisionNumber; -import org.hibernate.envers.RevisionTimestamp; - -/** - * This is a custom {@link org.hibernate.envers.DefaultRevisionEntity revision entity} also containing the actual user. - * - * @see org.hibernate.envers.DefaultRevisionEntity - * - * @author hohwille - */ -@Entity -@RevisionEntity(AdvancedRevisionListener.class) -@Table(name = "REVINFO") -public class AdvancedRevisionEntity implements PersistenceEntity { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getId() */ - @Id - @GeneratedValue - @RevisionNumber - private Long id; - - /** @see #getTimestamp() */ - @RevisionTimestamp - private long timestamp; - - /** @see #getDate() */ - private transient Date date; - - /** @see #getUser() */ - private String user; - - /** - * The constructor. - */ - public AdvancedRevisionEntity() { - - super(); - } - - @Override - public Long getId() { - - return this.id; - } - - /** - * @param id is the new value of {@link #getId()}. - */ - public void setId(Long id) { - - this.id = id; - } - - /** - * @return the timestamp when this revision has been created. - */ - public long getTimestamp() { - - return this.timestamp; - } - - /** - * @return the {@link #getTimestamp() timestamp} as {@link Date}. - */ - public Date getDate() { - - if (this.date == null) { - this.date = new Date(this.timestamp); - } - return this.date; - } - - /** - * @param timestamp is the new value of {@link #getTimestamp()}. - */ - public void setTimestamp(long timestamp) { - - this.timestamp = timestamp; - } - - /** - * @return the login or id of the user that has created this revision. - */ - public String getUser() { - - return this.user; - } - - /** - * @param user is the new value of {@link #getUser()}. - */ - public void setUser(String user) { - - this.user = user; - } - - @Override - public int getModificationCounter() { - - return 0; - } - - @Override - public Number getRevision() { - - return null; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionListener.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionListener.java deleted file mode 100644 index 40cb87726..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/AdvancedRevisionListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.api; - -import net.sf.mmm.util.session.api.UserSessionAccess; - -import org.hibernate.envers.RevisionListener; - -/** - * This is the implementation of {@link RevisionListener} that enriches {@link AdvancedRevisionEntity} with additional - * information. - * - * @author hohwille - */ -public class AdvancedRevisionListener implements RevisionListener { - - /** - * The constructor. - */ - public AdvancedRevisionListener() { - - super(); - } - - @Override - public void newRevision(Object revisionEntity) { - - AdvancedRevisionEntity revision = (AdvancedRevisionEntity) revisionEntity; - revision.setUser(UserSessionAccess.getUserLogin()); - } - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericRevisionedDao.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericRevisionedDao.java deleted file mode 100644 index 2fe22bd32..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericRevisionedDao.java +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.List; - -import javax.persistence.PersistenceException; - -import net.sf.mmm.util.entity.api.RevisionedEntity; -import net.sf.mmm.util.exception.api.ObjectNotFoundException; - -/** - * This is the interface for a {@link GenericDao} with the ability of revision-control. It organizes a revision-history - * (journal) of the managed entities. - * - * @see RevisionedEntity - * - * @param is the type of the {@link RevisionedEntity#getId() primary key}. - * @param is the type of the managed entity. - * - * @author Joerg Hohwiller (hohwille at users.sourceforge.net) - */ -public interface GenericRevisionedDao> extends GenericDao { - - /** - * This method will get the {@link List} of historic {@link MutablePersistenceEntity#getRevision() revisions} of the - * {@link MutablePersistenceEntity entity} with the given id.
- * If the entity is NOT revision controlled, an {@link java.util.Collections#emptyList() empty list} is - * returned. - * - * @param id the {@link MutablePersistenceEntity#getId() primary key} of the {@link MutablePersistenceEntity entity} - * to retrieve the history for. - * @return the {@link List} of historic {@link RevisionedEntity#getRevision() revisions}. - */ - List getRevisionHistory(ID id); - - /** - * This method will get the {@link List} of {@link RevisionMetadata} from the {@link RevisionedEntity#getRevision() - * revision}-history of the entity with the given id. - * - * @param id is the {@link RevisionedEntity#getId() primary key} of the entity for which the history-metadata is - * requested. - * @return the requested {@link List} of {@link RevisionMetadata}. - */ - List getRevisionHistoryMetadata(Object id); - - /** - * This method loads a historic {@link RevisionedEntity#getRevision() revision} of the {@link RevisionedEntity} with - * the given id from the persistent store.
- * However if the given revision is {@link RevisionedEntity#LATEST_REVISION} the {@link #find(Object) - * latest revision will be loaded}.
- * ATTENTION:
- * You should not make assumptions about the revision numbering of the underlying implementation. Please - * use {@link #getRevisionHistory(Object)} or {@link #getRevisionHistoryMetadata(Object)} to find revision numbers. - * - * @param id is the {@link RevisionedEntity#getId() primary key} of the requested {@link RevisionedEntity entity}. - * @param revision is the {@link RevisionedEntity#getRevision() revision} of the requested entity or - * {@link RevisionedEntity#LATEST_REVISION} to get the {@link #find(Object) latest} revision. A specific - * revision has to be greater than 0. - * @return the requested {@link RevisionedEntity entity}. - * @throws ObjectNotFoundException if the requested {@link RevisionedEntity entity} could NOT be found. - */ - ENTITY load(ID id, Number revision) throws ObjectNotFoundException; - - /** - * {@inheritDoc} - * - * The behavior of this method depends on the revision-control strategy of the implementation.
- *
    - *
  • In case of an audit-proof revision-history the deletion of the - * {@link RevisionedEntity#LATEST_REVISION latest revision} of an entity will only move it to the history while the - * deletion of a {@link RevisionedEntity#getRevision() historic entity} is NOT permitted and will cause a - * {@link PersistenceException}.
  • - *
  • In case of an on-demand revision-history the deletion of the {@link RevisionedEntity#LATEST_REVISION - * latest revision} of an entity will either move it to the history or
  • - *
- * If the given entity is a {@link RevisionedEntity#getRevision() historic entity} the according historic - */ - @Override - void delete(ENTITY entity); - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionMetadata.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionMetadata.java deleted file mode 100644 index d3838d2de..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionMetadata.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.Date; - -/** - * This is the interface for the metadata associated with a - * {@link net.sf.mmm.util.entity.api.RevisionedEntity#getRevision() historic revision} of an - * {@link net.sf.mmm.util.entity.api.RevisionedEntity entity}. - * - * @author hohwille - */ -public interface RevisionMetadata { - - /** - * This method gets the {@link net.sf.mmm.util.entity.api.RevisionedEntity#getRevision() revision number}. - * - * @return the revision number. - */ - Number getRevision(); - - /** - * This method gets the date when this revision was created (closed). - * - * @return the date of completion or {@code null} if the according entity is the latest revision. - */ - Date getDate(); - - /** - * This method gets the identifier (login) of the author who created this revision. - * - * @return the author. May be {@code null} (if committed outside user scope). - */ - String getAuthor(); - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedDao.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedDao.java deleted file mode 100644 index 555687364..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedDao.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -/** - * This is a simplified variant of {@link GenericRevisionedDao} for the suggested and common case that you have a - * {@link Long} as {@link MutablePersistenceEntity#getId() primary key}. - * - * @param is the type of the managed {@link MutablePersistenceEntity entity}. - * @author hohwille - */ -public interface RevisionedDao> extends - GenericRevisionedDao { - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedMasterDataDao.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedMasterDataDao.java deleted file mode 100644 index 3a730680e..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/api/RevisionedMasterDataDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * This is the interface for a {@link Dao} responsible for a {@link PersistenceEntity} that represents master-data. In - * that case you typically have a limited number of entities in your persistent store and need operations like - * {@link #findAll()}.
- * ATTENTION:
- * Such operations are not part of {@link GenericDao} or {@link Dao} as invoking them (accidently) could cause that an - * extraordinary large number of entities are loaded into main memory and could cause serious performance and stability - * disasters. So only extend this interface in case you are aware of what you are doing. - * - * @param is the generic type of the {@link PersistenceEntity}. - * - * @author hohwille - */ -public interface RevisionedMasterDataDao> extends GenericRevisionedDao { - - /** - * @return an {@link Iterable} with ALL managed entities from the persistent store. Not exposed to API by default as - * this might not make sense for all kind of entities. - */ - List findAll(); - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericRevisionedDao.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericRevisionedDao.java deleted file mode 100644 index e7ddc6386..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericRevisionedDao.java +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.GenericRevisionedDao; -import io.oasp.module.jpa.dataaccess.api.RevisionMetadata; -import io.oasp.module.jpa.dataaccess.api.MutablePersistenceEntity; -import io.oasp.module.jpa.dataaccess.impl.LazyRevisionMetadata; - -import java.util.ArrayList; -import java.util.List; - -import net.sf.mmm.util.exception.api.ObjectNotFoundException; - -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; - -/** - * This is the abstract base-implementation of a {@link AbstractGenericDao} using {@link org.hibernate.envers - * Hibernate-Envers} to manage the revision-control. - * - * @param is the type of the {@link MutablePersistenceEntity#getId() primary key} of the managed - * {@link MutablePersistenceEntity entity}. - * @param is the {@link #getEntityClass() type} of the managed entity. - * - * @author hohwille - */ -public abstract class AbstractGenericRevisionedDao> extends - AbstractGenericDao implements GenericRevisionedDao { - - /** - * The constructor. - */ - public AbstractGenericRevisionedDao() { - - super(); - } - - /** - * @return the auditReader - */ - protected AuditReader getAuditReader() { - - return AuditReaderFactory.get(getEntityManager()); - } - - @Override - public ENTITY load(ID id, Number revision) throws ObjectNotFoundException { - - if (revision == MutablePersistenceEntity.LATEST_REVISION) { - return find(id); - } else { - return loadRevision(id, revision); - } - } - - /** - * This method gets a historic revision of the {@link net.sf.mmm.util.entity.api.GenericEntity} with the given - * id. - * - * @param id is the {@link net.sf.mmm.util.entity.api.GenericEntity#getId() ID} of the requested - * {@link net.sf.mmm.util.entity.api.GenericEntity entity}. - * @param revision is the {@link MutablePersistenceEntity#getRevision() revision} - * @return the requested {@link net.sf.mmm.util.entity.api.GenericEntity entity}. - */ - protected ENTITY loadRevision(Object id, Number revision) { - - Class entityClassImplementation = getEntityClass(); - ENTITY entity = getAuditReader().find(entityClassImplementation, id, revision); - if (entity != null) { - entity.setRevision(revision); - } - return entity; - } - - @Override - public List getRevisionHistory(ID id) { - - return getAuditReader().getRevisions(getEntityClass(), id); - } - - @Override - public List getRevisionHistoryMetadata(Object id) { - - AuditReader auditReader = getAuditReader(); - List revisionList = auditReader.getRevisions(getEntityClass(), id); - List result = new ArrayList<>(); - for (Number revision : revisionList) { - Long revisionLong = Long.valueOf(revision.longValue()); - result.add(new LazyRevisionMetadata(getEntityManager(), revisionLong)); - } - return result; - } -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractRevisionedDao.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractRevisionedDao.java deleted file mode 100644 index 421df13de..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractRevisionedDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.RevisionedDao; -import io.oasp.module.jpa.dataaccess.api.MutablePersistenceEntity; - -/** - * Abstract base implementation of {@link RevisionedDao} interface. - * - * @param is the type of the managed {@link MutablePersistenceEntity entity}. - * @author hohwille - */ -public abstract class AbstractRevisionedDao> extends - AbstractGenericRevisionedDao implements RevisionedDao { - -} diff --git a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/impl/LazyRevisionMetadata.java b/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/impl/LazyRevisionMetadata.java deleted file mode 100644 index 55607fb7e..000000000 --- a/oasp4j-modules/oasp4j-jpa-envers/src/main/java/io/oasp/module/jpa/dataaccess/impl/LazyRevisionMetadata.java +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.impl; - -import io.oasp.module.jpa.dataaccess.api.AdvancedRevisionEntity; -import io.oasp.module.jpa.dataaccess.api.RevisionMetadata; - -import java.util.Date; - -import javax.persistence.EntityManager; - -/** - * This is a lazy implementation of the {@link RevisionMetadata} interface. - * - * @author hohwille - */ -public class LazyRevisionMetadata implements RevisionMetadata { - - /** The {@link EntityManager} used to read the metadata. */ - private final EntityManager entityManager; - - /** @see #getRevision() */ - private final Long revision; - - /** @see #getRevisionEntity() */ - private AdvancedRevisionEntity revisionEntity; - - /** - * The constructor. - * - * @param entityManager is the {@link EntityManager} used to fetch metadata. - * @param revision is the {@link #getRevision() revision}. - */ - public LazyRevisionMetadata(EntityManager entityManager, Long revision) { - - super(); - this.entityManager = entityManager; - this.revision = revision; - } - - /** - * @return the revisionEntity - */ - public AdvancedRevisionEntity getRevisionEntity() { - - if (this.revisionEntity == null) { - this.revisionEntity = this.entityManager.find(AdvancedRevisionEntity.class, this.revision); - assert (this.revisionEntity != null); - } - return this.revisionEntity; - } - - @Override - public String getAuthor() { - - return getRevisionEntity().getUser(); - } - - @Override - public Date getDate() { - - return getRevisionEntity().getDate(); - } - - @Override - public Number getRevision() { - - return this.revision; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/pom.xml b/oasp4j-modules/oasp4j-jpa/pom.xml deleted file mode 100644 index 8eddc359c..000000000 --- a/oasp4j-modules/oasp4j-jpa/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-jpa - ${oasp4j.version} - jar - ${project.artifactId} - JPA-based persistence infrastructure of the Open Application Standard Platform for Java (OASP4J). - - - - net.sf.m-m-m - mmm-util-core - - - org.hibernate.javax.persistence - hibernate-jpa-2.1-api - - - com.mysema.querydsl - querydsl-jpa - - - org.hibernate - hibernate-entitymanager - true - - - - io.oasp.java.modules - oasp4j-test - test - - - io.oasp.java.modules - oasp4j-configuration - test - - - org.springframework - spring-orm - test - - - org.springframework - spring-context - test - - - com.h2database - h2 - test - - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderBy.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderBy.java deleted file mode 100644 index 244066978..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderBy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -/** - * {@link Enum} for sort order. - * - * @author jozitz - */ -public enum OrderBy { - - /** Sort in ascending order. */ - ASC, - - /** Sort in descending order. */ - DESC; - - /** - * @return {@code true}, if {@link OrderBy#ASC} is set. {@code false} otherwise. - */ - public boolean isAsc() { - - return this == ASC; - } - - /** - * @return {@code true}, if {@link OrderBy#DESC} is set. {@code false} otherwise. - */ - public boolean isDesc() { - - return this == DESC; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderByTo.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderByTo.java deleted file mode 100644 index 2ab6e93bd..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/OrderByTo.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * Transfer object to transmit order criteria - */ -public class OrderByTo extends AbstractTransferObject { - - private static final long serialVersionUID = 1L; - - private String name; - - private OrderBy direction; - - /** - * The constructor. - */ - public OrderByTo() { - - super(); - } - - /** - * Returns the field 'name'. - * - * @return Value of name - */ - public String getName() { - - return this.name; - } - - /** - * Sets the field 'name'. - * - * @param name New value for name - */ - public void setName(String name) { - - this.name = name; - } - - /** - * Returns the field 'direction'. - * - * @return Value of direction - */ - public OrderBy getDirection() { - - return this.direction; - } - - /** - * Sets the field 'direction'. - * - * @param direction New value for direction - */ - public void setDirection(OrderBy direction) { - - this.direction = direction; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginatedListTo.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginatedListTo.java deleted file mode 100644 index 5956e9f7f..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginatedListTo.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.transferobject.api.CompositeTo; -import net.sf.mmm.util.transferobject.api.TransferObject; - -/** - * A paginated list of objects with additional pagination information. - * - * @param is the generic type of the objects. Will usually be a {@link PersistenceEntity persistent entity} when - * used in the data layer, or a {@link TransferObject transfer object}. - * - * @author henning - */ -public class PaginatedListTo extends CompositeTo { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getPagination() */ - private PaginationResultTo pagination; - - /** @see #getResult() */ - private List result; - - /** - * A convenience constructor which accepts a paginated list and {@link PaginationResultTo pagination information}. - * - * @param result is the list of objects. - * @param pagination is the {@link PaginationResultTo pagination information}. - */ - public PaginatedListTo(List result, PaginationResultTo pagination) { - - this.result = result; - this.pagination = pagination; - } - - /** - * @return the list of objects. - */ - public List getResult() { - - return this.result; - } - - /** - * @return pagination is the {@link PaginationResultTo pagination information}. - */ - public PaginationResultTo getPagination() { - - return this.pagination; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationResultTo.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationResultTo.java deleted file mode 100644 index b4acd8317..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationResultTo.java +++ /dev/null @@ -1,90 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -import net.sf.mmm.util.exception.api.NlsIllegalArgumentException; -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * Pagination information about a paginated query. - * - * @author henning - */ -public class PaginationResultTo extends AbstractTransferObject { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getSize() */ - private Integer size; - - /** @see #getPage() */ - private int page = 1; - - /** @see #getTotal() */ - private Long total; - - /** - * Constructor expecting an existing {@link PaginationTo pagination criteria} and the total number of results found. - * - * @param pagination is an existing {@link PaginationTo pagination criteria}. - * @param total is the total number of results found without pagination. - */ - public PaginationResultTo(PaginationTo pagination, Long total) { - - super(); - - setPage(pagination.getPage()); - setSize(pagination.getSize()); - setTotal(total); - } - - /** - * @return size the size of a page. - */ - public Integer getSize() { - - return this.size; - } - - /** - * @param size the size of a page. - */ - public void setSize(Integer size) { - - this.size = size; - } - - /** - * @return page the current page. - */ - public int getPage() { - - return this.page; - } - - /** - * @param page the current page. Must be greater than 0. - */ - public void setPage(int page) { - - if (page <= 0) { - throw new NlsIllegalArgumentException(page, "page"); - } - this.page = page; - } - - /** - * @return total the total number of entities - */ - public Long getTotal() { - - return this.total; - } - - /** - * @param total the total number of entities - */ - public void setTotal(Long total) { - - this.total = total; - } -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationTo.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationTo.java deleted file mode 100644 index 8c067e898..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/PaginationTo.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -import net.sf.mmm.util.exception.api.NlsIllegalArgumentException; -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * A {@link net.sf.mmm.util.transferobject.api.TransferObject transfer-object } containing criteria for paginating - * queries. - * - * @author henning - */ -public class PaginationTo extends AbstractTransferObject { - - /** - * Empty {@link PaginationTo} indicating no pagination. - */ - public static final PaginationTo NO_PAGINATION = new PaginationTo(); - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getSize() */ - private Integer size; - - /** @see #getPage() */ - private int page = 1; - - /** @see #isTotal() */ - private boolean total; - - /** - * @return size the size of a page. - */ - public Integer getSize() { - - return this.size; - } - - /** - * @param size the size of a page. - */ - public void setSize(Integer size) { - - this.size = size; - } - - /** - * @return page the current page. - */ - public int getPage() { - - return this.page; - } - - /** - * @param page the current page. Must be greater than 0. - */ - public void setPage(int page) { - - if (page <= 0) { - throw new NlsIllegalArgumentException(page, "page"); - } - this.page = page; - } - - /** - * @return total is {@code true} if the client requests that the server calculates the total number of entries found. - */ - public boolean isTotal() { - - return this.total; - } - - /** - * @param total is {@code true} to request calculation of the total number of entries. - */ - public void setTotal(boolean total) { - - this.total = total; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/SearchCriteriaTo.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/SearchCriteriaTo.java deleted file mode 100644 index 3cff51a8e..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/common/api/to/SearchCriteriaTo.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.oasp.module.jpa.common.api.to; - -import java.util.List; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * This is the interface for a {@link net.sf.mmm.util.transferobject.api.TransferObject transfer-object } with the - * criteria for a search and pagination query. Such object specifies the criteria selecting which hits will match when - * performing a search.
- * NOTE:
- * This interface only holds the necessary settings for the pagination part of a query. For your individual search, you - * extend {@link SearchCriteriaTo} to create a java bean with all the fields for your search. - * - * @author hohwille - */ -public class SearchCriteriaTo extends AbstractTransferObject { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getPagination() */ - private PaginationTo pagination; - - /** @see getSearchTimeout */ - private Integer searchTimeout; - - /** @see #getSort() */ - private List sort; - - /** - * The constructor. - */ - public SearchCriteriaTo() { - - super(); - } - - /** - * The currently active pagination. - * - * @return pagination the currently active pagination or {@link PaginationTo#NO_PAGINATION} if no specific pagination - * has been set. Will never return {@code null}. - */ - public PaginationTo getPagination() { - - return this.pagination == null ? PaginationTo.NO_PAGINATION : this.pagination; - } - - /** - * @param pagination the pagination to set - */ - public void setPagination(PaginationTo pagination) { - - this.pagination = pagination; - } - - /** - * Limits the {@link PaginationTo#getSize() page size} by the given limit. - *

- * If currently no pagination is active, or the {@link PaginationTo#getSize() current page size} is {@code null} or - * greater than the given {@code limit}, the value is replaced by {@code limit} - * - * @param limit is the maximum allowed value for the {@link PaginationTo#getSize() page size}. - */ - public void limitMaximumPageSize(int limit) { - - if (getPagination() == PaginationTo.NO_PAGINATION) { - setPagination(new PaginationTo()); - } - - Integer pageSize = getPagination().getSize(); - if ((pageSize == null) || (pageSize.intValue() > limit)) { - getPagination().setSize((Integer.valueOf(limit))); - } - } - - /** - * This method gets the maximum delay in milliseconds the search may last until it is canceled.
- * Note:
- * This feature is the same as the query hint "javax.persistence.query.timeout" in JPA. - * - * @return the search timeout in milliseconds or {@code null} for NO timeout. - */ - public Integer getSearchTimeout() { - - return this.searchTimeout; - } - - /** - * @param searchTimeout is the new value of {@link #getSearchTimeout()}. - */ - public void setSearchTimeout(int searchTimeout) { - - this.searchTimeout = searchTimeout; - } - - /** - * @return sort Sort criterias list - */ - public List getSort() { - - return this.sort; - } - - /** - * @param sort Set the sort criterias list - */ - public void setSort(List sort) { - - this.sort = sort; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/AbstractPersistenceEntity.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/AbstractPersistenceEntity.java deleted file mode 100644 index 117dde33b..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/AbstractPersistenceEntity.java +++ /dev/null @@ -1,139 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.Objects; - -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.MappedSuperclass; -import javax.persistence.Transient; -import javax.persistence.Version; - -/** - * Abstract base implementation of {@link MutablePersistenceEntity} with a {@link GeneratedValue generated} - * {@link #getId() primary key}. In case you need a different type of key add it as extra column and make it - * {@link javax.persistence.Column#unique() unique}. - * - * @author hohwille - * @author rjoeris - */ -@MappedSuperclass -public abstract class AbstractPersistenceEntity implements MutablePersistenceEntity { - - private static final long serialVersionUID = 1L; - - /** @see #getId() */ - private Long id; - - /** @see #getModificationCounter() */ - private int modificationCounter; - - /** @see #getRevision() */ - private Number revision; - - /** - * The constructor. - */ - public AbstractPersistenceEntity() { - - super(); - } - - @Override - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - public Long getId() { - - return this.id; - } - - public void setId(Long id) { - - this.id = id; - } - - @Override - @Version - public int getModificationCounter() { - - return this.modificationCounter; - } - - @Override - public void setModificationCounter(int version) { - - this.modificationCounter = version; - } - - @Override - @Transient - public Number getRevision() { - - return this.revision; - } - - /** - * @param revision the revision to set - */ - public void setRevision(Number revision) { - - this.revision = revision; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = 1; - result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); - result = prime * result + this.modificationCounter; - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AbstractPersistenceEntity other = (AbstractPersistenceEntity) obj; - if (!Objects.equals(this.id, other.id)) { - return false; - } - if (this.modificationCounter != other.modificationCounter) { - return false; - } - return true; - } - - @Override - public String toString() { - - StringBuilder buffer = new StringBuilder(); - toString(buffer); - return buffer.toString(); - } - - /** - * Method to extend {@link #toString()} logic. - * - * @param buffer is the {@link StringBuilder} where to {@link StringBuilder#append(Object) append} the string - * representation. - */ - protected void toString(StringBuilder buffer) { - - buffer.append(getClass().getSimpleName()); - if (this.id != null) { - buffer.append("[id="); - buffer.append(this.id); - buffer.append("]"); - } - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/Dao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/Dao.java deleted file mode 100644 index 6945305dd..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/Dao.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * This is a simplified variant of {@link GenericDao} for the suggested and common case that you have a {@link Long} as - * {@link PersistenceEntity#getId() primary key}. - * - * @see GenericDao - * @see AbstractPersistenceEntity - * - * @param is the generic type of the {@link PersistenceEntity}. - * - * @author hohwille - */ -public interface Dao> extends GenericDao { - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericDao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericDao.java deleted file mode 100644 index abcee993b..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/GenericDao.java +++ /dev/null @@ -1,123 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; - -/** - * This is the interface for a Data Access Object (DAO). It acts as a manager responsible for the persistence - * operations on a specific {@link PersistenceEntity entity} {@literal }.
- * This is base interface contains the CRUD operations: - *

    - *
  • Create: call {@link #save(PersistenceEntity)} on a new entity.
  • - *
  • Retrieve: use find* methods such as {@link #findOne(Object)}. More specific queries will be added in - * dedicated DAO interfaces.
  • - *
  • Update: done automatically by JPA vendor (hibernate) on commit or call {@link #save(PersistenceEntity)} to - * {@link javax.persistence.EntityManager#merge(Object) merge} an entity.
  • - *
  • Delete: call {@link #delete(PersistenceEntity)} or {@link #delete(Object)}.
  • - *
- * For each (non-abstract) implementation of {@link PersistenceEntity entity} MyEntity you should create an - * interface interface MyEntityDao that inherits from this {@link GenericDao} interface. Also you create an - * implementation of that interface MyEntityDaoImpl that you derive from - * {@link io.oasp.module.jpa.dataaccess.base.AbstractGenericDao}. - * - * @param is the generic type if the {@link PersistenceEntity#getId() primary key}. - * @param is the generic type of the {@link PersistenceEntity}. - * - * @author hohwille - */ -public interface GenericDao> { - - /** - * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the - * entity instance completely. - * - * @param entity the {@link PersistenceEntity entity} to save - * @return the saved entity - */ - E save(E entity); - - /** - * Saves all given entities. - * - * @param entities the {@link PersistenceEntity entities} to save - */ - void save(Iterable entities); - - /** - * Retrieves an entity by its id. - * - * @param id must not be {@literal null}. - * @return the entity with the given id or {@literal null} if none found - * @throws ObjectNotFoundUserException if the requested entity does not exists (use {@link #findOne(Object)} to - * prevent). - */ - E find(ID id) throws ObjectNotFoundUserException; - - /** - * Retrieves an entity by its id. - * - * @param id must not be {@literal null}. - * @return the entity with the given id or {@literal null} if none found - * @throws IllegalArgumentException if {@code id} is {@code null} - */ - E findOne(ID id) throws IllegalArgumentException; - - /** - * Returns whether an entity with the given id exists. - * - * @param id must not be {@literal null}. - * @return true if an entity with the given id exists, {@literal false} otherwise - */ - boolean exists(ID id); - - /** - * Returns all instances of the type with the given IDs. - * - * @param ids are the IDs of all entities to retrieve e.g. as {@link java.util.List}. - * @return an {@link Iterable} with all {@link PersistenceEntity entites} for the given ids. - */ - List findAll(Iterable ids); - - /** - * Deletes the entity with the given id. - * - * @param id must not be {@literal null}. - * @throws IllegalArgumentException in case the given {@code id} is {@code null} - */ - void delete(ID id) throws IllegalArgumentException; - - /** - * Deletes a given entity. - * - * @param entity the {@link PersistenceEntity entity} to delete - */ - void delete(E entity); - - /** - * Deletes the given entities. - * - * @param entities the {@link PersistenceEntity entities} to delete - */ - void delete(Iterable entities); - - /** - * Enforces to increment the {@link PersistenceEntity#getModificationCounter() modificationCounter} e.g. to enforce - * that a parent object gets locked when its children are modified.
- * As an example we assume that we have the two optimistic locked entities {@code Order} and its contained - * {@code OrderPosition}. By default the users can modify an {@code Order} and each of its {@code OrderPosition}s in - * parallel without getting a locking conflict. This can be desired. However, it can also be a demand that an - * {@code Order} gets approved and the user doing that is responsible for the total price as the sum of the prices of - * each {@code OrderPosition}. Now if another user is adding or changing an {@code OrderPostion} belonging to that - * {@code Order} in parallel the {@code Order} will get approved but the approved total price will differ from what - * the user has actually seen when he clicked on approve. To prevent this the use-case to modify an - * {@code OrderPosition} can use this method to trigger a locking on the associated {@code Order}. The implication is - * also that two users changing an {@code OrderPosition} associated with the same {@code Order} in parallel will get a - * conflict. - * - * @param entity that is getting checked. - */ - void forceIncrementModificationCounter(E entity); - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MasterDataDao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MasterDataDao.java deleted file mode 100644 index 2e742955f..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MasterDataDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.oasp.module.jpa.dataaccess.api; - -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * This is the interface for a {@link Dao} responsible for a {@link PersistenceEntity} that represents master-data. In - * that case you typically have a limited number of entities in your persistent store and need operations like - * {@link #findAll()}.
- * ATTENTION:
- * Such operations are not part of {@link GenericDao} or {@link Dao} as invoking them (accidently) could cause that an - * extraordinary large number of entities are loaded into main memory and could cause serious performance and stability - * disasters. So only extend this interface in case you are aware of what you are doing. - * - * @param is the generic type of the {@link PersistenceEntity}. - * - * @author hohwille - */ -public interface MasterDataDao> extends Dao { - - /** - * @return an {@link Iterable} with ALL managed entities from the persistent store. Not exposed to API by default as - * this might not make sense for all kind of entities. - */ - List findAll(); - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MutablePersistenceEntity.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MutablePersistenceEntity.java deleted file mode 100644 index 24c3a4e32..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/api/MutablePersistenceEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 */ -package io.oasp.module.jpa.dataaccess.api; - -import net.sf.mmm.util.entity.api.MutableGenericEntity; -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * This is the interface for a {@link PersistenceEntity} in OASP. - * - * @param is the type of the {@link #getId() primary key}. - * - * @see AbstractPersistenceEntity - * - * @author hohwille - */ -public interface MutablePersistenceEntity extends PersistenceEntity, MutableGenericEntity { - - /** - * This method sets the {@link #getRevision() revision} of this entity.
- * ATTENTION:
- * This operation should only be used in specific cases and if you are aware of what you are doing as this attribute - * is managed by the persistence. However, for final freedom we decided to add this method to the API (e.g. to copy - * from transfer-object to persistent-entity and vice-versa). - * - * @param revision is the new value of {@link #getRevision()}. - */ - void setRevision(Number revision); - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractDao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractDao.java deleted file mode 100644 index 0ad832748..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractDao.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.Dao; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * Abstract base implementation of {@link Dao} interface. - * - * @param is the generic type of the {@link PersistenceEntity}. Should be derived from - * {@link io.oasp.module.jpa.dataaccess.api.AbstractPersistenceEntity}. - * - * @author hohwille - */ -public abstract class AbstractDao> extends AbstractGenericDao implements - Dao { - - /** - * The constructor. - */ - public AbstractDao() { - - super(); - } - -} \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDao.java deleted file mode 100644 index 92a053a9a..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDao.java +++ /dev/null @@ -1,363 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.common.api.to.PaginatedListTo; -import io.oasp.module.jpa.common.api.to.PaginationResultTo; -import io.oasp.module.jpa.common.api.to.PaginationTo; -import io.oasp.module.jpa.common.api.to.SearchCriteriaTo; -import io.oasp.module.jpa.dataaccess.api.GenericDao; - -import java.util.List; - -import javax.persistence.EntityManager; -import javax.persistence.EntityNotFoundException; -import javax.persistence.LockModeType; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.persistence.TypedQuery; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; - -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; -import net.sf.mmm.util.search.base.AbstractSearchCriteria; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.mysema.query.jpa.impl.JPAQuery; -import com.mysema.query.types.Expression; - -/** - * This is the abstract base-implementation of the {@link GenericDao} interface. - * - * @param is the generic type if the {@link PersistenceEntity#getId() primary key}. - * @param is the generic type of the managed {@link PersistenceEntity}. - * - * @author hohwille - */ -// @Repository -public abstract class AbstractGenericDao> implements GenericDao { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericDao.class); - - private EntityManager entityManager; - - /** - * The constructor. - */ - public AbstractGenericDao() { - - super(); - } - - /** - * @return the {@link Class} reflecting the managed entity. - */ - protected abstract Class getEntityClass(); - - /** - * @return the {@link EntityManager} instance. - */ - protected EntityManager getEntityManager() { - - return this.entityManager; - } - - /** - * @param entityManager the {@link EntityManager} to inject. - */ - @PersistenceContext - public void setEntityManager(EntityManager entityManager) { - - this.entityManager = entityManager; - } - - /** - * @return the name of the managed entity. - */ - protected String getEntityName() { - - return getEntityClass().getSimpleName(); - } - - @Override - public E save(E entity) { - - if (isNew(entity)) { - this.entityManager.persist(entity); - LOG.debug("Saved new {} with id {}.", getEntityName(), entity.getId()); - return entity; - } else { - if (this.entityManager.find(entity.getClass(), entity.getId()) != null) { - E update = this.entityManager.merge(entity); - LOG.debug("Updated {} with id {}.", getEntityName(), entity.getId()); - return update; - } else { - throw new EntityNotFoundException("Entity not found"); - } - } - } - - /** - * Determines if the given {@link PersistenceEntity} is {@link PersistenceEntity#STATE_NEW new}. - * - * @param entity is the {@link PersistenceEntity} to check. - * @return {@code true} if {@link PersistenceEntity#STATE_NEW new}, {@code false} otherwise (e.g. - * {@link PersistenceEntity#STATE_DETACHED detached} or {@link PersistenceEntity#STATE_MANAGED managed}. - */ - protected boolean isNew(E entity) { - - return entity.getId() == null; - } - - @Override - public void save(Iterable entities) { - - for (E entity : entities) { - save(entity); - } - } - - @Override - public void forceIncrementModificationCounter(E entity) { - - getEntityManager().lock(entity, LockModeType.OPTIMISTIC_FORCE_INCREMENT); - } - - @Override - public E findOne(ID id) { - - E entity = this.entityManager.find(getEntityClass(), id); - return entity; - } - - @Override - public E find(ID id) throws ObjectNotFoundUserException { - - E entity = findOne(id); - if (entity == null) { - throw new ObjectNotFoundUserException(getEntityClass().getSimpleName(), id); - } - return entity; - } - - @Override - public boolean exists(ID id) { - - // pointless... - return findOne(id) != null; - } - - /** - * @return an {@link Iterable} to find ALL {@link #getEntityClass() managed entities} from the persistent store. Not - * exposed to API by default as this might not make sense for all kind of entities. - */ - protected List findAll() { - - CriteriaQuery query = this.entityManager.getCriteriaBuilder().createQuery(getEntityClass()); - Root root = query.from(getEntityClass()); - query.select(root); - TypedQuery typedQuery = this.entityManager.createQuery(query); - List resultList = typedQuery.getResultList(); - LOG.debug("Query for all {} objects returned {} hit(s).", getEntityName(), resultList.size()); - return resultList; - } - - @Override - public List findAll(Iterable ids) { - - CriteriaBuilder builder = this.entityManager.getCriteriaBuilder(); - CriteriaQuery query = builder.createQuery(getEntityClass()); - Root root = query.from(getEntityClass()); - query.select(root); - query.where(root.get("id").in(ids)); - TypedQuery typedQuery = this.entityManager.createQuery(query); - List resultList = typedQuery.getResultList(); - LOG.debug("Query for selection of {} objects returned {} hit(s).", getEntityName(), resultList.size()); - return resultList; - } - - @Override - public void delete(ID id) { - - E entity = this.entityManager.getReference(getEntityClass(), id); - this.entityManager.remove(entity); - LOG.debug("Deleted {} with ID {}.", getEntityName(), id); - } - - @Override - public void delete(E entity) { - - // entity might be detached and could cause trouble in entityManager on remove - if (this.entityManager.contains(entity)) { - this.entityManager.remove(entity); - LOG.debug("Deleted {} with ID {}.", getEntityName(), entity.getId()); - } else { - delete(entity.getId()); - } - - } - - @Override - public void delete(Iterable entities) { - - for (E entity : entities) { - delete(entity); - } - } - - @SuppressWarnings("javadoc") - protected PaginatedListTo findPaginated(SearchCriteriaTo criteria, Query query, Expression expr) { - - throw new UnsupportedOperationException("Pagination is not yet supported for generic JPA queries."); - } - - /** - * Returns a paginated list of entities according to the supplied {@link SearchCriteriaTo criteria}. - *

- * Applies {@code limit} and {@code offset} values to the supplied {@query} according to the supplied - * {@link PaginationTo pagination} information inside {@code criteria}. - *

- * If a {@link PaginationTo#isTotal() total count} of available entities is requested, will also execute a second - * query, without pagination parameters applied, to obtain said count. - *

- * Will install a query timeout if {@link SearchCriteriaTo#getSearchTimeout()} is not null. - * - * @param criteria contains information about the requested page. - * @param query is a query which is preconfigured with the desired conditions for the search. - * @param expr is used for the final mapping from the SQL result to the entities. - * @return a paginated list. - */ - protected PaginatedListTo findPaginated(SearchCriteriaTo criteria, JPAQuery query, Expression expr) { - - applyCriteria(criteria, query); - - PaginationTo pagination = criteria.getPagination(); - - PaginationResultTo paginationResult = createPaginationResult(pagination, query); - - applyPagination(pagination, query); - List paginatedList = query.list(expr); - - return new PaginatedListTo<>(paginatedList, paginationResult); - } - - /** - * Creates a {@link PaginationResultTo pagination result} for the given {@code pagination} and {@code query}. - *

- * Needs to be called before pagination is applied to the {@code query}. - * - * @param pagination contains information about the requested page. - * @param query is a query preconfigured with the desired conditions for the search. - * @return information about the applied pagination. - */ - protected PaginationResultTo createPaginationResult(PaginationTo pagination, JPAQuery query) { - - Long total = calculateTotalBeforePagination(pagination, query); - - return new PaginationResultTo(pagination, total); - } - - /** - * Calculates the total number of entities the given {@link JPAQuery query} would return without pagination applied. - *

- * Needs to be called before pagination is applied to the {@code query}. - * - * @param pagination is the pagination information as requested by the client. - * @param query is the {@link JPAQuery query} for which to calculate the total. - * @return the total count, or {@literal null} if {@link PaginationTo#isTotal()} is {@literal false}. - */ - protected Long calculateTotalBeforePagination(PaginationTo pagination, JPAQuery query) { - - Long total = null; - if (pagination.isTotal()) { - total = query.clone().count(); - } - - return total; - } - - /** - * Applies the {@link PaginationTo pagination criteria} to the given {@link JPAQuery}. - * - * @param pagination is the {@link PaginationTo pagination criteria} to apply. - * @param query is the {@link JPAQuery} to apply to. - */ - protected void applyPagination(PaginationTo pagination, JPAQuery query) { - - if (pagination == PaginationTo.NO_PAGINATION) { - return; - } - - Integer limit = pagination.getSize(); - if (limit != null) { - query.limit(limit); - - int page = pagination.getPage(); - if (page > 0) { - query.offset((page - 1) * limit); - } - } - } - - /** - * Applies the meta-data of the given {@link AbstractSearchCriteria search criteria} to the given {@link JPAQuery}. - * - * @param criteria is the {@link AbstractSearchCriteria search criteria} to apply. - * @param query is the {@link JPAQuery} to apply to. - */ - protected void applyCriteria(AbstractSearchCriteria criteria, JPAQuery query) { - - Integer limit = criteria.getMaximumHitCount(); - if (limit != null) { - query.limit(limit); - } - int offset = criteria.getHitOffset(); - if (offset > 0) { - query.offset(offset); - } - Long timeout = criteria.getSearchTimeout(); - if (timeout != null) { - query.setHint("javax.persistence.query.timeout", timeout.intValue()); - } - } - - /** - * Applies the meta-data of the given {@link AbstractSearchCriteria search criteria} to the given {@link Query}. - * - * @param criteria is the {@link AbstractSearchCriteria search criteria} to apply. - * @param query is the {@link Query} to apply to. - */ - protected void applyCriteria(AbstractSearchCriteria criteria, Query query) { - - Integer limit = criteria.getMaximumHitCount(); - if (limit != null) { - query.setMaxResults(limit); - } - int offset = criteria.getHitOffset(); - if (offset > 0) { - query.setFirstResult(offset); - } - Long timeout = criteria.getSearchTimeout(); - if (timeout != null) { - query.setHint("javax.persistence.query.timeout", timeout.intValue()); - } - } - - /** - * Applies the meta-data of the given {@link SearchCriteriaTo search criteria} to the given {@link Query}. - * - * @param criteria is the {@link AbstractSearchCriteria search criteria} to apply. - * @param query is the {@link JPAQuery} to apply to. - */ - protected void applyCriteria(SearchCriteriaTo criteria, JPAQuery query) { - - Integer timeout = criteria.getSearchTimeout(); - if (timeout != null) { - query.setHint("javax.persistence.query.timeout", timeout.intValue()); - } - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractMasterDataDao.java b/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractMasterDataDao.java deleted file mode 100644 index 6608fc4dc..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/AbstractMasterDataDao.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.MasterDataDao; - -import java.util.List; - -import net.sf.mmm.util.entity.api.PersistenceEntity; - -/** - * This is the abstract base implementation of {@link MasterDataDao}. - * - * @param is the generic type of the {@link PersistenceEntity}. Should be derived from - * {@link io.oasp.module.jpa.dataaccess.api.AbstractPersistenceEntity}. - * - * @author hohwille - */ -public abstract class AbstractMasterDataDao> extends AbstractDao implements - MasterDataDao { - - /** - * The constructor. - */ - public AbstractMasterDataDao() { - - super(); - } - - @Override - public List findAll() { - - return super.findAll(); - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDaoTest.java b/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDaoTest.java deleted file mode 100644 index 547611b9a..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/AbstractGenericDaoTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.configuration.common.api.ApplicationConfigurationConstants; -import io.oasp.module.jpa.dataaccess.api.GenericDao; -import io.oasp.module.test.common.base.ComponentTest; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.transaction.Transactional; - -import org.junit.Test; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; - -/** - * Test class to test the {@link GenericDao}. - * - * @author fawinter - */ -@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class }) -@ContextConfiguration({ ApplicationConfigurationConstants.BEANS_DATA_ACCESS }) -public class AbstractGenericDaoTest extends ComponentTest { - - @Inject - private GenericDaoForceIncrementModificationTestBean testBean; - - /** - * Test of {@link GenericDao#forceIncrementModificationCounter(net.sf.mmm.util.entity.api.PersistenceEntity)}. Ensures - * that the modification counter is updated after the call of that method when the transaction is closed. - */ - @Test - public void testForceIncrementModificationCounter() { - - // given - TestEntity entity = this.testBean.create(); - assertThat(entity.getId()).isNotNull(); - assertThat(entity.getModificationCounter()).isEqualTo(0); - - // when - TestEntity updatedEntity = this.testBean.incrementModificationCounter(entity.getId()); - - // then - assertThat(updatedEntity.getModificationCounter()).isEqualTo(1); - } - - /** - * This type provides methods in a transactional environment for the containing test class. All methods, annotated - * with the {@link Transactional} annotation, are executed in separate transaction, thus one test case can execute - * multiple transactions. Unfortunately this does not work when the transactional methods are directly in the - * top-level class of the test-case itself. - */ - @Named - public static class GenericDaoForceIncrementModificationTestBean { - - @Inject - private TestDao genericDao; - - /** - * Creates a new {@link TestEntity}, persist it and surround everything with a transaction. - * - * @return entity the new {@link TestEntity}. - */ - @Transactional - public TestEntity create() { - - TestEntity entity = new TestEntity(); - this.genericDao.save(entity); - return entity; - } - - /** - * Loads the {@link TestEntity} with the given {@code id} and - * {@link GenericDao#forceIncrementModificationCounter(net.sf.mmm.util.entity.api.PersistenceEntity) increments the - * modification counter}. - * - * @param id of the {@link TestEntity} to load and increment. - * @return entity the updated {@link TestEntity}. - */ - @Transactional - public TestEntity incrementModificationCounter(long id) { - - TestEntity entity = this.genericDao.find(id); - this.genericDao.forceIncrementModificationCounter(entity); - return entity; - } - } - -}; diff --git a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDao.java b/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDao.java deleted file mode 100644 index c74bf1cb0..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDao.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.Dao; - -/** - * Test interface for {@link AbstractGenericDaoTest}. - * - * @author fawinter - */ -public interface TestDao extends Dao { - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDaoImpl.java b/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDaoImpl.java deleted file mode 100644 index 8895cb483..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestDaoImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import javax.inject.Named; - -/** - * Implementation of {@link TestDao}. - * - * @author fawinter - */ -@Named -public class TestDaoImpl extends AbstractDao implements TestDao { - - @Override - protected Class getEntityClass() { - - return TestEntity.class; - } - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestEntity.java b/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestEntity.java deleted file mode 100644 index 078e8a522..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/java/io/oasp/module/jpa/dataaccess/base/TestEntity.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import io.oasp.module.jpa.dataaccess.api.AbstractPersistenceEntity; - -import javax.persistence.Entity; - -/** - * This is a test entity for {@link AbstractGenericDaoTest}. - * - * @author fawinter - */ -@Entity -public class TestEntity extends AbstractPersistenceEntity { - - private static final long serialVersionUID = 1L; - -} diff --git a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/application-default.properties b/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/application-default.properties deleted file mode 100644 index 42b1d4ed5..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/application-default.properties +++ /dev/null @@ -1,13 +0,0 @@ -# --------------------------------------------------------------------------- -# Persistence and database -# --------------------------------------------------------------------------- -database.user.login = sa -database.user.password = -database.url = jdbc:h2:./target/.sample;INIT=create schema if not exists public -database.hibernate.dialect = org.hibernate.dialect.H2Dialect -database.datasource = org.h2.jdbcx.JdbcDataSource -database.hibernate.hbm2ddl.auto = create -database.hibernate.show.sql = false - -# Activate spring profiles -#spring.profiles.active = integrationTest diff --git a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/common/beans-common.xml b/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/common/beans-common.xml deleted file mode 100644 index d42fe16f0..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/common/beans-common.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - classpath:/config/app/application-default.properties - - - - - - diff --git a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-dataaccess.xml b/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-dataaccess.xml deleted file mode 100644 index 2368bf945..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-dataaccess.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - diff --git a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-db-plain.xml b/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-db-plain.xml deleted file mode 100644 index 72c85cf37..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-db-plain.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-jpa.xml b/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-jpa.xml deleted file mode 100644 index bb51ac146..000000000 --- a/oasp4j-modules/oasp4j-jpa/src/test/resources/config/app/dataaccess/beans-jpa.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - io.oasp.module.jpa.dataaccess - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-modules/oasp4j-logging/.checkstyle b/oasp4j-modules/oasp4j-logging/.checkstyle deleted file mode 100644 index b6203b021..000000000 --- a/oasp4j-modules/oasp4j-logging/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/oasp4j-modules/oasp4j-logging/pom.xml b/oasp4j-modules/oasp4j-logging/pom.xml deleted file mode 100644 index 7c1e1c309..000000000 --- a/oasp4j-modules/oasp4j-logging/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-logging - ${oasp4j.version} - jar - ${project.artifactId} - Logging Module of the Open Application Standard Platform for Java (OASP4J). - - - - ch.qos.logback - logback-classic - - - org.slf4j - jcl-over-slf4j - - - javax.servlet - javax.servlet-api - provided - - - org.springframework - spring-web - true - - - javax.inject - javax.inject - - - org.codehaus.janino - janino - - - - io.oasp.java.modules - oasp4j-test - test - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/DiagnosticContextFacade.java b/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/DiagnosticContextFacade.java deleted file mode 100644 index cb3a6e066..000000000 --- a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/DiagnosticContextFacade.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.oasp.module.logging.common.api; - -/** - * This is the interface for a simple facade to write data into the {@link org.slf4j.MDC mapped diagnostic context}. As - * additional value you can easily hook in custom extensions without interfering the logger implementation. A use case - * may be to provide diagnostic informations also to additional components such as a performance monitoring module. - * Therefore setting diagnostic information from OASP code is always indirected via this interface so the implementation - * can be extended or replaced (what is not as easy for {@link org.slf4j.MDC#put(String, String) static methods}). - * - * @author hohwille - */ -public interface DiagnosticContextFacade { - - /** - * @return the current {@link LoggingConstants#CORRELATION_ID correlation ID} or {@code null} if not - * {@link #setCorrelationId(String) set}. - */ - String getCorrelationId(); - - /** - * Sets the {@link LoggingConstants#CORRELATION_ID correlation ID} for the current processing and thread. - * - * @param correlationId is the {@link LoggingConstants#CORRELATION_ID correlation ID} as unique identifier for the - * current processing task. - */ - void setCorrelationId(String correlationId); - - /** - * Removes the {@link #setCorrelationId(String) correlation ID} from the diagnostic context. - */ - void removeCorrelationId(); - -} diff --git a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/LoggingConstants.java b/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/LoggingConstants.java deleted file mode 100644 index 0e558619a..000000000 --- a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/api/LoggingConstants.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.oasp.module.logging.common.api; - -/** - * Central constants for logging. - * - * @author rstroh - */ -public final class LoggingConstants { - - /** - * The key for the correlation id used as unique identifier to correlate log entries of a processing task. It allows - * to track down all related log messages for that task across the entire application landscape (e.g. in case of a - * problem). - * - * @see DiagnosticContextFacade#setCorrelationId(String) - */ - public static final String CORRELATION_ID = "correlationId"; - - /** - * Construction prohibited. - */ - private LoggingConstants() { - - super(); - } - -} diff --git a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFacadeImpl.java b/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFacadeImpl.java deleted file mode 100644 index e4be6c0a2..000000000 --- a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFacadeImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.oasp.module.logging.common.impl; - -import io.oasp.module.logging.common.api.DiagnosticContextFacade; -import io.oasp.module.logging.common.api.LoggingConstants; - -import org.slf4j.MDC; - -/** - * This is the simple and straight forward implementation of {@link DiagnosticContextFacade}. - * - * @author hohwille - */ -public class DiagnosticContextFacadeImpl implements DiagnosticContextFacade { - - /** - * The constructor. - */ - public DiagnosticContextFacadeImpl() { - - super(); - } - - @Override - public String getCorrelationId() { - - return MDC.get(LoggingConstants.CORRELATION_ID); - } - - @Override - public void setCorrelationId(String correlationId) { - - MDC.put(LoggingConstants.CORRELATION_ID, correlationId); - } - - @Override - public void removeCorrelationId() { - - MDC.remove(LoggingConstants.CORRELATION_ID); - } - -} diff --git a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFilter.java b/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFilter.java deleted file mode 100644 index e6f0be328..000000000 --- a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/DiagnosticContextFilter.java +++ /dev/null @@ -1,156 +0,0 @@ -package io.oasp.module.logging.common.impl; - -import io.oasp.module.logging.common.api.DiagnosticContextFacade; - -import java.io.IOException; -import java.util.UUID; - -import javax.inject.Inject; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Request logging filter that adds the request log message to the SLF4j mapped diagnostic context (MDC) before the - * request is processed, removing it again after the request is processed. - * - * @author Malte Brunnlieb - * @author hohwille - */ -// @WebFilter("/services/*") -public class DiagnosticContextFilter implements Filter { - - private static final Logger LOG = LoggerFactory.getLogger(DiagnosticContextFilter.class); - - /** - * The name of the {@link FilterConfig#getInitParameter(String) init parameter} for - * {@link #setCorrelationIdHttpHeaderName(String)}. - */ - private static final String CORRELATION_ID_HEADER_NAME_PARAM = "correlationIdHeaderName"; - - /** The default value for {@link #setCorrelationIdHttpHeaderName(String)}. */ - private static final String CORRELATION_ID_HEADER_NAME_DEFAULT = "CorrelationId"; - - /** @see #setCorrelationIdHttpHeaderName(String) */ - private String correlationIdHttpHeaderName; - - private DiagnosticContextFacade diagnosticContextFacade; - - /** - * The constructor. - */ - public DiagnosticContextFilter() { - - super(); - } - - /** - * @param correlationIdHttpHeaderName is the name of the {@link HttpServletRequest#getHeader(String) HTTP header} for - * the {@link io.oasp.module.logging.common.api.LoggingConstants#CORRELATION_ID correlation ID}. - */ - public void setCorrelationIdHttpHeaderName(String correlationIdHttpHeaderName) { - - this.correlationIdHttpHeaderName = correlationIdHttpHeaderName; - } - - @Override - public void destroy() { - - } - - private static String normalizeValue(String value) { - - if (value != null) { - String result = value.trim(); - if (!result.isEmpty()) { - return result; - } - } - return null; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - - setCorrelationId(request); - try { - chain.doFilter(request, response); - } finally { - this.diagnosticContextFacade.removeCorrelationId(); - } - } - - private void setCorrelationId(ServletRequest request) { - - String correlationId = null; - if (request instanceof HttpServletRequest && this.correlationIdHttpHeaderName != null) { - correlationId = normalizeValue(((HttpServletRequest) request).getHeader(this.correlationIdHttpHeaderName)); - if (correlationId == null) { - LOG.debug("No correlation ID found for HTTP header {}.", this.correlationIdHttpHeaderName); - } else { - this.diagnosticContextFacade.setCorrelationId(correlationId); - LOG.debug("Using correlation ID {} from HTTP header {}.", correlationId, this.correlationIdHttpHeaderName); - return; - } - } - if (correlationId == null) { - // potential fallback if initialized before this filter... - correlationId = normalizeValue(this.diagnosticContextFacade.getCorrelationId()); - if (correlationId != null) { - LOG.debug("Correlation ID was already set to {} before DiagnosticContextFilter has been invoked.", - correlationId); - } else { - // no correlation ID present, create a unique ID - correlationId = UUID.randomUUID().toString(); - this.diagnosticContextFacade.setCorrelationId(correlationId); - LOG.debug("Created unique correlation ID {}.", correlationId); - } - } - } - - /** - * @param diagnosticContextFacade the diagnosticContextFacade to set - */ - @Inject - public void setDiagnosticContextFacade(DiagnosticContextFacade diagnosticContextFacade) { - - this.diagnosticContextFacade = diagnosticContextFacade; - } - - @Override - public void init(FilterConfig config) throws ServletException { - - String headerName = config.getInitParameter(CORRELATION_ID_HEADER_NAME_PARAM); - if (headerName == null) { - headerName = CORRELATION_ID_HEADER_NAME_DEFAULT; - LOG.info("Parameter {} not configured using default.", CORRELATION_ID_HEADER_NAME_PARAM); - } - this.correlationIdHttpHeaderName = headerName; - LOG.info("Correlation ID header initialized to: {}", this.correlationIdHttpHeaderName); - if (this.diagnosticContextFacade == null) { - try { - // ATTENTION: We do not import these classes as we keep spring as an optional dependency. - // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a - // ClassNotFoundException and use the fallback in the catch statement. - ServletContext servletContext = config.getServletContext(); - org.springframework.web.context.WebApplicationContext springContext; - springContext = - org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(servletContext); - this.diagnosticContextFacade = springContext.getBean(DiagnosticContextFacade.class); - } catch (Throwable e) { - LOG.warn("DiagnosticContextFacade not defined in spring. Falling back to default", e); - this.diagnosticContextFacade = new DiagnosticContextFacadeImpl(); - } - } - } - -} diff --git a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/SingleLinePatternLayout.java b/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/SingleLinePatternLayout.java deleted file mode 100644 index ff466fd5a..000000000 --- a/oasp4j-modules/oasp4j-logging/src/main/java/io/oasp/module/logging/common/impl/SingleLinePatternLayout.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.oasp.module.logging.common.impl; - -import java.util.regex.Pattern; - -import ch.qos.logback.classic.PatternLayout; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.classic.spi.IThrowableProxy; -import ch.qos.logback.classic.spi.StackTraceElementProxy; -import ch.qos.logback.core.CoreConstants; - -/** - * Custom {@link PatternLayout} for logging entries. - * - * @author rstroh - */ -public class SingleLinePatternLayout extends PatternLayout { - - // --------------- FIELDS --------------- - - /** The separator used as replacement for newlines. */ - private static final String LINE_SEP = " | "; - - /** OS specific line separator. */ - private static final String NEWLINE = CoreConstants.LINE_SEPARATOR; - - /** Regular expression for line breaks. */ - private static final Pattern LINEBREAK_PATTERN = Pattern.compile("[\\r\\n|\\n]"); - - /** Average buffer size per line of stack trace. */ - private static final int BUFFER_PER_LINE = 50; - - // --------------- CONSTRUCTORS --------------- - - /** - * Default constructor. - */ - public SingleLinePatternLayout() { - - super(); - } - - // --------------- METHODS --------------- - - /** - * Creates formatted String, using conversion pattern. - * - * @param event ILoggingEvent - * @return String Formatted event as string in one line - */ - @Override - public String doLayout(ILoggingEvent event) { - - // Format message - String msg = super.doLayout(event).trim(); - // prevent log forging - msg = preventLogForging(msg); - - // Formatting of exception, remove line breaks - IThrowableProxy throwableProxy = event.getThrowableProxy(); - if (throwableProxy != null) { - StackTraceElementProxy[] s = throwableProxy.getStackTraceElementProxyArray(); - if (s != null && s.length > 0) { - // Performance: Initialize StringBuilder with (number of StackTrace-Elements + 1)*50 (+1 for Message) - StringBuilder sb = new StringBuilder(s.length * BUFFER_PER_LINE); - sb.append(msg); - - int len = s.length; - for (int i = 0; i < len; i++) { - sb.append(LINE_SEP).append(s[i]); - } - msg = sb.toString(); - } - } - return msg + NEWLINE; - } - - /** - * Method to prevent log forging. - * - * @param logMsg - * @return Encoded message - */ - private String preventLogForging(String logMsg) { - - String result = logMsg; - // use precompiled pattern for performance reasons - result = LINEBREAK_PATTERN.matcher(logMsg).replaceAll(SingleLinePatternLayout.LINE_SEP); - return result; - } - -} diff --git a/oasp4j-modules/oasp4j-rest/pom.xml b/oasp4j-modules/oasp4j-rest/pom.xml deleted file mode 100644 index 2e39482c9..000000000 --- a/oasp4j-modules/oasp4j-rest/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-rest - ${oasp4j.version} - jar - ${project.artifactId} - REST-Service Support Module of the Open Application Standard Platform for Java (OASP4J). - - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - - - javax.ws.rs - javax.ws.rs-api - - - org.slf4j - slf4j-api - - - javax.inject - javax.inject - - - javax.validation - validation-api - - - org.springframework - spring-context - - - net.sf.m-m-m - mmm-util-core - - - org.springframework.security - spring-security-core - test - - - - org.glassfish.jersey.core - jersey-common - 2.4.1 - test - - - io.oasp.java.modules - oasp4j-test - test - - - org.hibernate - hibernate-validator - test - - - javax.el - javax.el-api - - - org.glassfish.web - javax.el - - - - diff --git a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/api/RequestParameters.java b/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/api/RequestParameters.java deleted file mode 100644 index 99f8afb1a..000000000 --- a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/api/RequestParameters.java +++ /dev/null @@ -1,213 +0,0 @@ -package io.oasp.module.rest.service.api; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -import javax.ws.rs.BadRequestException; -import javax.ws.rs.InternalServerErrorException; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.UriInfo; - -/** - * This class helps to deal with {@link UriInfo} and {@link MultivaluedMap} from the JAX-RS API. E.g. if you have a REST - * query operation for a collection URI you can use {@link UriInfo} in case you want to support a mixture of optional - * and required parameters. The methods provided here throw according exceptions such as {@link BadRequestException} and - * already support conversion of values. - * - * @author hohwille - */ -public class RequestParameters { - - private final MultivaluedMap parameters; - - /** - * The constructor. - * - * @param parameters is the {@link MultivaluedMap} containing the parameters to wrap. - */ - public RequestParameters(MultivaluedMap parameters) { - - super(); - this.parameters = parameters; - } - - /** - * Gets the single parameter in a generic and flexible way. - * - * @param is the generic type of targetType. - * @param key is the {@link java.util.Map#get(Object) key} of the parameter to get. - * @param targetType is the {@link Class} reflecting the type to convert the value to. Supports common Java standard - * types such as {@link String}, {@link Long}, {@link Double}, {@link BigDecimal}, etc. - * @param required - {@code true} if the value is required and a {@link BadRequestException} is thrown if it is - * not present, {@code false} otherwise (if optional). - * @return the value for the given key converted to the given targetType. May be - * {@code null} if required is {@code false} . - * @throws WebApplicationException if an error occurred. E.g. {@link BadRequestException} if a required parameter is - * missing or {@link InternalServerErrorException} if the given targetType is not supported. - */ - @SuppressWarnings("unchecked") - public T get(String key, Class targetType, boolean required) throws WebApplicationException { - - String value = get(key); - if (value == null) { - if (required) { - throw new BadRequestException("Missing parameter: " + key); - } - Object result = null; - if (targetType.isPrimitive()) { - if (targetType == boolean.class) { - result = Boolean.FALSE; - } else if (targetType == int.class) { - result = Integer.valueOf(0); - } else if (targetType == long.class) { - result = Long.valueOf(0); - } else if (targetType == double.class) { - result = Double.valueOf(0); - } else if (targetType == float.class) { - result = Float.valueOf(0); - } else if (targetType == byte.class) { - result = Byte.valueOf((byte) 0); - } else if (targetType == short.class) { - result = Short.valueOf((short) 0); - } else if (targetType == char.class) { - result = '\0'; - } - } - return (T) result; - } - try { - return convertValue(value, targetType); - } catch (WebApplicationException e) { - throw e; - } catch (Exception e) { - throw new BadRequestException("Failed to convert '" + value + "' to type " + targetType); - } - } - - /** - * Converts the given value to the given targetType. - * - * @param is the generic type of targetType. - * @param value is the value to convert. - * @param targetType is the {@link Class} reflecting the type to convert the value to. - * @return the converted value. - * @throws ParseException if parsing of the given value failed while converting. - */ - @SuppressWarnings("unchecked") - protected T convertValue(String value, Class targetType) throws ParseException { - - if (value == null) { - return null; - } - Object result; - if (targetType == String.class) { - result = value; - } else if (targetType.isEnum()) { - for (T instance : targetType.getEnumConstants()) { - Enum e = (Enum) instance; - if (e.name().equalsIgnoreCase(value)) { - return instance; - } - } - throw new IllegalArgumentException("Enum constant not found!"); - } else if ((targetType == boolean.class) || (targetType == Boolean.class)) { - result = Boolean.parseBoolean(value); - } else if ((targetType == int.class) || (targetType == Integer.class)) { - result = Integer.valueOf(value); - } else if ((targetType == long.class) || (targetType == Long.class)) { - result = Long.valueOf(value); - } else if ((targetType == double.class) || (targetType == Double.class)) { - result = Double.valueOf(value); - } else if ((targetType == float.class) || (targetType == Float.class)) { - result = Float.valueOf(value); - } else if ((targetType == short.class) || (targetType == Short.class)) { - result = Short.valueOf(value); - } else if ((targetType == byte.class) || (targetType == Byte.class)) { - result = Byte.valueOf(value); - } else if (targetType == BigDecimal.class) { - result = new BigDecimal(value); - } else if (targetType == BigInteger.class) { - result = new BigInteger(value); - } else if (targetType == Date.class) { - result = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss").parseObject(value); - } else { - throw new InternalServerErrorException("Unsupported type " + targetType); - } - // do not use type.cast() as not working for primitive types. - return (T) result; - } - - /** - * Gets the parameter as single value with the given key as {@link String}. - * - * @param key is the {@link java.util.Map#get(Object) key} of the parameter to get. - * @return the requested parameter. Will be {@code null} if the parameter is not present. - * @throws BadRequestException if the parameter is defined multiple times (see {@link #getList(String)}). - */ - public String get(String key) throws BadRequestException { - - List list = this.parameters.get(key); - if ((list == null) || (list.isEmpty())) { - return null; - } - if (list.size() > 1) { - throw new BadRequestException("Duplicate parameter: " + key); - } - return list.get(0); - } - - /** - * Gets the parameter with the given key as {@link String}. Unlike {@link #get(String)} this method will - * not throw an exception if the parameter is multi-valued but just return the first value. - * - * @param key is the {@link java.util.Map#get(Object) key} of the parameter to get. - * @return the first value of the requested parameter. Will be {@code null} if the parameter is not present. - */ - public String getFirst(String key) { - - return this.parameters.getFirst(key); - } - - /** - * Gets the {@link List} of all value for the parameter with with the given key. In general you should - * avoid multi-valued parameters (e.g. http://host/path?query=a&query=b). The JAX-RS API supports this exotic case as - * first citizen so we expose it here but only use it if you know exactly what you are doing. - * - * @param key is the {@link java.util.Map#get(Object) key} of the parameter to get. - * @return the {@link List} with all values of the requested parameter. Will be an {@link Collections#emptyList() - * empty list} if the parameter is not present. - */ - public List getList(String key) { - - List list = this.parameters.get(key); - if (list == null) { - list = Collections.emptyList(); - } - return list; - } - - /** - * @param uriInfo is the {@link UriInfo}. - * @return a new instance of {@link RequestParameters} for {@link UriInfo#getQueryParameters()}. - */ - public static RequestParameters fromQuery(UriInfo uriInfo) { - - return new RequestParameters(uriInfo.getQueryParameters()); - } - - /** - * @param uriInfo is the {@link UriInfo}. - * @return a new instance of {@link RequestParameters} for {@link UriInfo#getPathParameters()}. - */ - public static RequestParameters fromPath(UriInfo uriInfo) { - - return new RequestParameters(uriInfo.getPathParameters()); - } - -} diff --git a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacade.java b/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacade.java deleted file mode 100644 index 124cd5ad1..000000000 --- a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacade.java +++ /dev/null @@ -1,451 +0,0 @@ -package io.oasp.module.rest.service.impl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import javax.inject.Inject; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Path.Node; -import javax.validation.ValidationException; -import javax.ws.rs.ClientErrorException; -import javax.ws.rs.ServerErrorException; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -import net.sf.mmm.util.exception.api.NlsRuntimeException; -import net.sf.mmm.util.exception.api.TechnicalErrorUserException; -import net.sf.mmm.util.lang.api.StringUtil; -import net.sf.mmm.util.security.api.SecurityErrorUserException; -import net.sf.mmm.util.validation.api.ValidationErrorUserException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * This is an implementation of {@link ExceptionMapper} that acts as generic exception facade for REST services. - * - * the exception handling class for all upcoming exceptions thrown at REST requests. Each type of possible thrown - * exception will be fetched within the method "toResponse". - * - * @author agreul - */ -@Provider -public class RestServiceExceptionFacade implements ExceptionMapper { - - /** JSON key for {@link Throwable#getMessage() error message}. */ - public static final String KEY_MESSAGE = "message"; - - /** JSON key for {@link NlsRuntimeException#getUuid() error ID}. */ - public static final String KEY_UUID = "uuid"; - - /** JSON key for {@link NlsRuntimeException#getCode() error code}. */ - public static final String KEY_CODE = "code"; - - /** JSON key for {@link NlsRuntimeException#getCode() errors}. */ - public static final String KEY_ERRORS = "errors"; - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(RestServiceExceptionFacade.class); - - private final List> securityExceptions; - - private ObjectMapper mapper; - - private boolean exposeInternalErrorDetails; - - /** - * The constructor. - */ - public RestServiceExceptionFacade() { - - super(); - this.securityExceptions = new ArrayList<>(); - registerToplevelSecurityExceptions(); - } - - /** - * Registers a {@link Class} as a top-level security {@link Throwable exception}. Instances of this class and all its - * subclasses will be handled as security errors. Therefore an according HTTP error code is used and no further - * details about the exception is send to the client to prevent sensitive data exposure. - * - * @param securityException is the {@link Class} reflecting the security error. - */ - protected void registerToplevelSecurityException(Class securityException) { - - this.securityExceptions.add(securityException); - } - - /** - * This method registers the {@link #registerToplevelSecurityException(Class) top-level security exceptions}. You may - * override it to add additional or other classes. - */ - protected void registerToplevelSecurityExceptions() { - - this.securityExceptions.add(SecurityException.class); - this.securityExceptions.add(SecurityErrorUserException.class); - registerToplevelSecurityExceptions("org.springframework.security.access.AccessDeniedException"); - registerToplevelSecurityExceptions("org.springframework.security.authentication.AuthenticationServiceException"); - registerToplevelSecurityExceptions("org.springframework.security.authentication.AuthenticationCredentialsNotFoundException"); - registerToplevelSecurityExceptions("org.springframework.security.authentication.BadCredentialsException"); - registerToplevelSecurityExceptions("org.springframework.security.authentication.AccountExpiredException"); - } - - /** - * @param className the className to be registered - */ - protected void registerToplevelSecurityExceptions(String className) { - - try { - @SuppressWarnings("unchecked") - Class securityException = (Class) Class.forName(className); - registerToplevelSecurityException(securityException); - } catch (ClassNotFoundException e) { - LOG.info( - "Spring security was not found on classpath. Spring security exceptions will not be handled as such by {}", - getClass().getSimpleName()); - } - } - - @Override - public Response toResponse(Throwable exception) { - - // business exceptions - if (exception instanceof WebApplicationException) { - return createResponse((WebApplicationException) exception); - } else if (exception instanceof ValidationException) { - Throwable t = exception; - Map> errorsMap = null; - if (exception instanceof ConstraintViolationException) { - ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception; - Set> violations = constraintViolationException.getConstraintViolations(); - errorsMap = new HashMap<>(); - - for (ConstraintViolation violation : violations) { - Iterator it = violation.getPropertyPath().iterator(); - String fieldName = null; - - // Getting fieldname from the exception - while (it.hasNext()) { - fieldName = it.next().toString(); - } - - List errorsList = errorsMap.get(fieldName); - - if (errorsList == null) { - errorsList = new ArrayList<>(); - errorsMap.put(fieldName, errorsList); - } - - errorsList.add(violation.getMessage()); - - } - - t = new ValidationException(errorsMap.toString()); - } - ValidationErrorUserException error = new ValidationErrorUserException(t); - return createResponse(t, error, errorsMap); - } else if (exception instanceof ValidationErrorUserException) { - return createResponse(exception, (ValidationErrorUserException) exception, null); - } else { - Class exceptionClass = exception.getClass(); - for (Class securityError : this.securityExceptions) { - if (securityError.isAssignableFrom(exceptionClass)) { - return handleSecurityError(exception); - } - } - return handleGenericError(exception); - } - } - - /** - * Creates the {@link Response} for the given validation exception. - * - * @param exception is the original validation exception. - * @param error is the wrapped exception or the same as exception. - * @param errorsMap is a map with all validation errors - * @return the requested {@link Response}. - */ - protected Response createResponse(Throwable exception, ValidationErrorUserException error, - Map> errorsMap) { - - LOG.warn("Service failed due to validation failure.", error); - if (exception == error) { - return createResponse(Status.BAD_REQUEST, error, errorsMap); - } else { - return createResponse(Status.BAD_REQUEST, error, exception.getMessage(), errorsMap); - } - } - - /** - * Exception handling depending on technical Exception or not. - * - * @param exception the exception thrown - * @return the response build from error status - */ - protected Response handleGenericError(Throwable exception) { - - NlsRuntimeException userError = TechnicalErrorUserException.getOrCreateUserException(exception); - if (userError.isTechnical()) { - LOG.error("Service failed on server", exception); - } else { - LOG.warn("Service failed due to business error: {}", exception.getMessage()); - } - return createResponse(userError); - } - - /** - * Exception handling for security exceptions. - * - * @param exception the exception thrown - * @return the response build from error status - */ - protected Response handleSecurityError(Throwable exception) { - - // *** security error *** - NlsRuntimeException error; - if (exception instanceof NlsRuntimeException) { - error = (NlsRuntimeException) exception; - } else { - error = new SecurityErrorUserException(exception); - } - LOG.error("Service failed due to security error", error); - // NOTE: for security reasons we do not send any details about the error - // to the client! - String message; - String code = null; - if (this.exposeInternalErrorDetails) { - message = getExposedErrorDetails(error); - } else { - message = "forbidden"; - } - return createResponse(Status.FORBIDDEN, message, code, error.getUuid(), null); - } - - /** - * @param error is the {@link Throwable} to extract message details from. - * @return the exposed message(s). - */ - protected String getExposedErrorDetails(Throwable error) { - - StringBuilder buffer = new StringBuilder(); - Throwable e = error; - while (e != null) { - if (buffer.length() > 0) { - buffer.append(StringUtil.LINE_SEPARATOR); - } - buffer.append(e.getClass().getSimpleName()); - buffer.append(": "); - buffer.append(e.getLocalizedMessage()); - e = e.getCause(); - } - return buffer.toString(); - } - - /** - * Create the {@link Response} for the given {@link NlsRuntimeException}. - * - * @param error the generic {@link NlsRuntimeException}. - * @return the corresponding {@link Response}. - */ - protected Response createResponse(NlsRuntimeException error) { - - Status status; - if (error.isTechnical()) { - status = Status.INTERNAL_SERVER_ERROR; - } else { - status = Status.BAD_REQUEST; - } - return createResponse(status, error, null); - } - - /** - * Create a response message as a JSON-String from the given parts. - * - * @param status is the HTTP {@link Status}. - * @param error is the catched or wrapped {@link NlsRuntimeException}. - * @param errorsMap is a map with all validation errors - * @return the corresponding {@link Response}. - */ - protected Response createResponse(Status status, NlsRuntimeException error, Map> errorsMap) { - - String message; - if (this.exposeInternalErrorDetails) { - message = getExposedErrorDetails(error); - } else { - message = error.getLocalizedMessage(); - } - return createResponse(status, error, message, errorsMap); - } - - /** - * Create a response message as a JSON-String from the given parts. - * - * @param status is the HTTP {@link Status}. - * @param error is the catched or wrapped {@link NlsRuntimeException}. - * @param message is the JSON message attribute. - * @param errorsMap is a map with all validation errors - * @return the corresponding {@link Response}. - */ - protected Response createResponse(Status status, NlsRuntimeException error, String message, - Map> errorsMap) { - - return createResponse(status, error, message, error.getCode(), errorsMap); - } - - /** - * Create a response message as a JSON-String from the given parts. - * - * @param status is the HTTP {@link Status}. - * @param error is the catched or wrapped {@link NlsRuntimeException}. - * @param message is the JSON message attribute. - * @param code is the {@link NlsRuntimeException#getCode() error code}. - * @param errorsMap is a map with all validation errors - * @return the corresponding {@link Response}. - */ - protected Response createResponse(Status status, NlsRuntimeException error, String message, String code, - Map> errorsMap) { - - return createResponse(status, message, code, error.getUuid(), errorsMap); - } - - /** - * Create a response message as a JSON-String from the given parts. - * - * @param status is the HTTP {@link Status}. - * @param message is the JSON message attribute. - * @param code is the {@link NlsRuntimeException#getCode() error code}. - * @param uuid the {@link UUID} of the response message. - * @param errorsMap is a map with all validation errors - * @return the corresponding {@link Response}. - */ - protected Response createResponse(Status status, String message, String code, UUID uuid, - Map> errorsMap) { - - String json = createJsonErrorResponseMessage(message, code, uuid, errorsMap); - return Response.status(status).entity(json).build(); - } - - /** - * Create a response message as a JSON-String from the given parts. - * - * @param message the message of the response message - * @param code the code of the response message - * @param uuid the uuid of the response message - * @param errorsMap is a map with all validation errors - * @return the response message as a JSON-String - */ - protected String createJsonErrorResponseMessage(String message, String code, UUID uuid, - Map> errorsMap) { - - Map jsonMap = new HashMap<>(); - if (message != null) { - jsonMap.put(KEY_MESSAGE, message); - } - if (code != null) { - jsonMap.put(KEY_CODE, code); - } - if (uuid != null) { - jsonMap.put(KEY_UUID, uuid.toString()); - } - - if (errorsMap != null) { - jsonMap.put(KEY_ERRORS, errorsMap); - } - - String responseMessage = ""; - try { - responseMessage = this.mapper.writeValueAsString(jsonMap); - } catch (JsonProcessingException e) { - LOG.error("Exception facade failed to create JSON.", e); - responseMessage = "{}"; - } - return responseMessage; - - } - - /** - * Add a response message to an existing response. - * - * @param exception the {@link WebApplicationException}. - * @return the response with the response message added - */ - protected Response createResponse(WebApplicationException exception) { - - Response response = exception.getResponse(); - int statusCode = response.getStatus(); - Status status = Status.fromStatusCode(statusCode); - NlsRuntimeException error; - if (exception instanceof ServerErrorException) { - error = new TechnicalErrorUserException(exception); - LOG.error("Service failed on server", error); - return createResponse(status, error, null); - } else { - UUID uuid = UUID.randomUUID(); - if (exception instanceof ClientErrorException) { - LOG.warn("Service failed due to unexpected request. UUDI: {}, reason: {} ", uuid, exception.getMessage()); - } else { - LOG.warn("Service caused redirect or other error. UUID: {}, reason: {}", uuid, exception.getMessage()); - } - return createResponse(status, exception.getMessage(), String.valueOf(statusCode), uuid, null); - } - - } - - /** - * @return the {@link ObjectMapper} for JSON mapping. - */ - public ObjectMapper getMapper() { - - return this.mapper; - } - - /** - * @param mapper the mapper to set - */ - @Inject - public void setMapper(ObjectMapper mapper) { - - this.mapper = mapper; - } - - /** - * @param exposeInternalErrorDetails - {@code true} if internal exception details shall be exposed to clients - * (useful for debugging and testing), {@code false} if such details are hidden to prevent Sensitive Data Exposure - * (default, has to be used in production environment). - */ - public void setExposeInternalErrorDetails(boolean exposeInternalErrorDetails) { - - this.exposeInternalErrorDetails = exposeInternalErrorDetails; - if (exposeInternalErrorDetails) { - String message = - "****** Exposing of internal error details is enabled! This violates OWASP A6 (Sensitive Data Exposure) and shall only be used for testing/debugging and never in production. ******"; - LOG.warn(message); - // CHECKSTYLE:OFF (for development only) - System.err.println(message); - // CHECKSTYLE:ON - } - } - - /** - * @return exposeInternalErrorDetails the value set by {@link #setExposeInternalErrorDetails(boolean)}. - */ - public boolean isExposeInternalErrorDetails() { - - return this.exposeInternalErrorDetails; - } - -} diff --git a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java b/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java deleted file mode 100644 index 8533b8554..000000000 --- a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.oasp.module.rest.service.impl.json; - -import java.io.IOException; -import java.math.BigDecimal; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; - -/** - * Helper class to simplify implementation of {@link JsonDeserializer}. - * - * @author agreul, hohwiller - * @param the class to be deserialized - */ -public abstract class AbstractJsonDeserializer extends JsonDeserializer { - - /** - * @param type of value from node to get - * @param node parent node to deserialize - * @param fieldName the required key whose value is looked up - * @param type the same type as the expected value - * @return value from node to get - */ - @SuppressWarnings("unchecked") - protected V getRequiredValue(JsonNode node, String fieldName, Class type) { - - JsonNode childNode = node.get(fieldName); - if (childNode != null) { - - V value = null; - if (!childNode.isNull()) { - try { - if (type == String.class) { - value = type.cast(childNode.asText()); - } else if (type == BigDecimal.class) { - value = type.cast(new BigDecimal(childNode.asText())); - } else if (type == Boolean.class) { - value = (V) Boolean.valueOf(childNode.booleanValue()); - } else if (type == Integer.class) { - value = (V) Integer.valueOf(childNode.asText()); - } else if (type == Double.class) { - value = (V) Double.valueOf(childNode.asText()); - } else { - throw new IllegalArgumentException("Unsupported value type " + type.getName()); - } - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Failed to convert value to type " + type.getName(), e); - } - } - if (value != null) { - return value; - } - } - throw new IllegalStateException("Deserialization failed due to missing " + type.getSimpleName() + " field " - + fieldName + "!"); - } - - @Override - public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - - JsonNode node = jp.getCodec().readTree(jp); - return deserializeNode(node); - } - - /** - * @param node is the {@link JsonNode} with the value content to be deserialized - * @return the deserialized java object - */ - protected abstract T deserializeNode(JsonNode node); -} diff --git a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/MixInAnnotationsModule.java b/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/MixInAnnotationsModule.java deleted file mode 100644 index 71e54267a..000000000 --- a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/MixInAnnotationsModule.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.oasp.module.rest.service.impl.json; - -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeInfo.As; -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.databind.module.SimpleModule; - -/** - * A {@link SimpleModule} to extend Jackson to mixin annotations for polymorphic types. - * - * @author hohwille - * @author agreul - */ -public class MixInAnnotationsModule extends SimpleModule { - - private static final long serialVersionUID = 1L; - - private final Class[] polymorphicClasses; - - /** - * @param polymorphicClasses the classes reflecting JSON transfer-objects that are polymorphic. - */ - public MixInAnnotationsModule(Class... polymorphicClasses) { - - super("oasp.PolymorphyModule", new Version(1, 0, 0, null, ObjectMapperFactory.GROUP_ID, - ObjectMapperFactory.ARTIFACT_ID)); - this.polymorphicClasses = polymorphicClasses; - } - - @Override - public void setupModule(SetupContext context) { - - for (Class type : this.polymorphicClasses) { - context.setMixInAnnotations(type, JacksonPolymorphicAnnotation.class); - } - } - - /** - * The blueprint class for the following JSON-annotation allowing to convert from JSON to POJO and vice versa - * - * @author agreul - */ - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "@type") - public static class JacksonPolymorphicAnnotation { - - } - -} diff --git a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/ObjectMapperFactory.java b/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/ObjectMapperFactory.java deleted file mode 100644 index ba2cdb57f..000000000 --- a/oasp4j-modules/oasp4j-rest/src/main/java/io/oasp/module/rest/service/impl/json/ObjectMapperFactory.java +++ /dev/null @@ -1,143 +0,0 @@ -package io.oasp.module.rest.service.impl.json; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.jsontype.NamedType; -import com.fasterxml.jackson.databind.jsontype.SubtypeResolver; -import com.fasterxml.jackson.databind.module.SimpleModule; - -/** - * A generic factory to {@link #createInstance() create} instances of a Jackson {@link ObjectMapper}. It allows to - * configure the {@link ObjectMapper} for polymorphic transfer-objects. - * - * @see #setBaseClasses(Class...) - * @see #setSubtypes(NamedType...) - * - * @author hohwille - * @author agreul - */ -public class ObjectMapperFactory { - - static final String GROUP_ID = "io.oasp.java"; - - static final String ARTIFACT_ID = "oasp4j-rest"; - - private List> baseClassList; - - private List subtypeList; - - private SimpleModule extensionModule; - - /** - * The constructor. - */ - public ObjectMapperFactory() { - - super(); - } - - /** - * Gets access to a generic extension {@link SimpleModule module} for customizations to Jackson JSON mapping. - * - * @see SimpleModule#addSerializer(Class, com.fasterxml.jackson.databind.JsonSerializer) - * @see SimpleModule#addDeserializer(Class, com.fasterxml.jackson.databind.JsonDeserializer) - * - * @return extensionModule - */ - public SimpleModule getExtensionModule() { - - if (this.extensionModule == null) { - this.extensionModule = - new SimpleModule("oasp.ExtensionModule", new Version(1, 0, 0, null, GROUP_ID, ARTIFACT_ID)); - } - return this.extensionModule; - } - - /** - * @param baseClasses are the base classes that are polymorphic (e.g. abstract transfer-object classes that have - * sub-types). You also need to register all sub-types of these polymorphic classes via - * {@link #setSubtypes(NamedType...)}. - */ - public void setBaseClasses(Class... baseClasses) { - - this.baseClassList = Arrays.asList(baseClasses); - } - - /** - * @see #setBaseClasses(Class...) - * - * @param baseClasses the base-classes to add to {@link #setBaseClasses(Class...) base classes list}. - */ - public void addBaseClasses(Class... baseClasses) { - - if (this.baseClassList == null) { - this.baseClassList = new ArrayList<>(); - } - this.baseClassList.addAll(Arrays.asList(baseClasses)); - } - - /** - * @see #setSubtypes(NamedType...) - * - * @param subtypeList the {@link List} of {@link NamedType}s to register the subtypes. - */ - public void setSubtypeList(List subtypeList) { - - this.subtypeList = subtypeList; - } - - /** - * @see #setSubtypes(NamedType...) - * - * @param subtypes the {@link NamedType}s to add to {@link #setSubtypeList(List) sub-type list} for registration. - */ - public void addSubtypes(NamedType... subtypes) { - - if (this.subtypeList == null) { - this.subtypeList = new ArrayList<>(); - } - this.subtypeList.addAll(Arrays.asList(subtypes)); - } - - /** - * @param subtypeList the {@link NamedType}s as pair of {@link Class} reflecting a polymorphic sub-type together with - * its unique name in JSON format. - */ - public void setSubtypes(NamedType... subtypeList) { - - setSubtypeList(Arrays.asList(subtypeList)); - } - - /** - * @return an instance of {@link ObjectMapper} configured for polymorphic resolution. - */ - public ObjectMapper createInstance() { - - ObjectMapper mapper = new ObjectMapper(); - - if ((this.baseClassList != null) && (!this.baseClassList.isEmpty())) { - Class[] baseClasses = this.baseClassList.toArray(new Class[this.baseClassList.size()]); - SimpleModule polymorphyModule = new MixInAnnotationsModule(baseClasses); - mapper.registerModule(polymorphyModule); - } - - if (this.extensionModule != null) { - mapper.registerModule(this.extensionModule); - } - - if (this.subtypeList != null) { - SubtypeResolver subtypeResolver = mapper.getSubtypeResolver(); - for (NamedType subtype : this.subtypeList) { - subtypeResolver.registerSubtypes(subtype); - } - mapper.setSubtypeResolver(subtypeResolver); - } - - return mapper; - } - -} diff --git a/oasp4j-modules/oasp4j-rest/src/test/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacadeTest.java b/oasp4j-modules/oasp4j-rest/src/test/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacadeTest.java deleted file mode 100644 index 885416d84..000000000 --- a/oasp4j-modules/oasp4j-rest/src/test/java/io/oasp/module/rest/service/impl/RestServiceExceptionFacadeTest.java +++ /dev/null @@ -1,336 +0,0 @@ -package io.oasp.module.rest.service.impl; - -import io.oasp.module.test.common.base.ModuleTest; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.ValidationException; -import javax.validation.Validator; -import javax.validation.constraints.Min; -import javax.ws.rs.BadRequestException; -import javax.ws.rs.InternalServerErrorException; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.core.Response; - -import net.sf.mmm.util.exception.api.IllegalCaseException; -import net.sf.mmm.util.exception.api.NlsRuntimeException; -import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; -import net.sf.mmm.util.exception.api.TechnicalErrorUserException; -import net.sf.mmm.util.lang.api.StringUtil; -import net.sf.mmm.util.security.api.SecurityErrorUserException; -import net.sf.mmm.util.validation.api.ValidationErrorUserException; - -import org.junit.Test; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.AccountExpiredException; -import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.InternalAuthenticationServiceException; - -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Test-case for {@link RestServiceExceptionFacade}. - * - * @author hohwille - */ -public class RestServiceExceptionFacadeTest extends ModuleTest { - - /** Value of {@link TechnicalErrorUserException#getCode()}. */ - private static final String CODE_TECHNICAL_ERROR = "TechnicalError"; - - /** Placeholder for any UUID. */ - private static final String UUID_ANY = ""; - - /** - * @return the {@link RestServiceExceptionFacade} instance to test. - */ - protected RestServiceExceptionFacade getExceptionFacade() { - - RestServiceExceptionFacade facade = new RestServiceExceptionFacade(); - facade.setMapper(new ObjectMapper()); - return facade; - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with constraint violations - */ - @Test - public void testConstraintViolationExceptions() { - - class CounterTest { - - @Min(value = 10) - private Integer count; - - public CounterTest(Integer count) { - - this.count = count; - } - - } - - CounterTest counter = new CounterTest(new Integer(1)); - - Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); - Set> violations = validator.validate(counter); - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String message = "{count=[" + violations.iterator().next().getMessage() + "]}"; - String errors = "{count=[" + violations.iterator().next().getMessage() + "]}"; - Throwable error = new ConstraintViolationException(violations); - checkFacade(exceptionFacade, error, 400, message, UUID_ANY, ValidationErrorUserException.CODE, errors); - - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with forbidden security exception including - * subclasses. - */ - @Test - public void testSecurityExceptions() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - - String secretMessage = "Secret information not to be revealed on client - only to be logged on server!"; - - int statusCode = 403; - String message = "forbidden"; - String code = null; - - checkFacade(exceptionFacade, new AccessDeniedException(secretMessage), statusCode, message, UUID_ANY, code); - checkFacade(exceptionFacade, new AuthenticationCredentialsNotFoundException(secretMessage), statusCode, message, - UUID_ANY, code, null); - checkFacade(exceptionFacade, new BadCredentialsException(secretMessage), statusCode, message, UUID_ANY, code); - checkFacade(exceptionFacade, new AccountExpiredException(secretMessage), statusCode, message, UUID_ANY, code); - checkFacade(exceptionFacade, new InternalAuthenticationServiceException(secretMessage), statusCode, message, - UUID_ANY, code, null); - SecurityErrorUserException error = new SecurityErrorUserException(); - checkFacade(exceptionFacade, error, statusCode, message, error.getUuid().toString(), code); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with forbidden security exception including - * subclasses. - */ - @Test - public void testSecurityExceptionExposed() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - exceptionFacade.setExposeInternalErrorDetails(true); - - String secretMessage = "Secret information not to be revealed on client - only to be logged on server!"; - - int statusCode = 403; - String message = - "The operation failed due to security restrictions. Please contact the support in case of a permission problem."; - String code = null; - - checkFacade(exceptionFacade, new AccessDeniedException(secretMessage), statusCode, "SecurityErrorUserException: " - + message + StringUtil.LINE_SEPARATOR + "AccessDeniedException: " + secretMessage, UUID_ANY, code); - } - - /** - * Checks that the specified {@link RestServiceExceptionFacade} provides the expected results for the given - * {@link Throwable}. - * - * @param exceptionFacade is the {@link RestServiceExceptionFacade} to test. - * @param error is the {@link Throwable} to convert. - * @param statusCode is the expected {@link Response#getStatus() status} code. - * @param message is the expected {@link Throwable#getMessage() error message} from the JSON result. - * @param uuid is the expected {@link NlsRuntimeException#getUuid() UUID} from the JSON result. May be - * {@code null}. - * @param code is the expected {@link NlsRuntimeException#getCode() error code} from the JSON result. May be - * {@code null}. - * @return the JSON result for potential further asserts. - */ - protected String checkFacade(RestServiceExceptionFacade exceptionFacade, Throwable error, int statusCode, - String message, String uuid, String code) { - - return checkFacade(exceptionFacade, error, statusCode, message, uuid, code, null); - } - - /** - * Checks that the specified {@link RestServiceExceptionFacade} provides the expected results for the given - * {@link Throwable}. - * - * @param exceptionFacade is the {@link RestServiceExceptionFacade} to test. - * @param error is the {@link Throwable} to convert. - * @param statusCode is the expected {@link Response#getStatus() status} code. - * @param message is the expected {@link Throwable#getMessage() error message} from the JSON result. - * @param uuid is the expected {@link NlsRuntimeException#getUuid() UUID} from the JSON result. May be - * {@code null}. - * @param code is the expected {@link NlsRuntimeException#getCode() error code} from the JSON result. May be - * {@code null}. - * @param errors is the expected validation errors in a format key-value - * @return the JSON result for potential further asserts. - */ - @SuppressWarnings("unchecked") - protected String checkFacade(RestServiceExceptionFacade exceptionFacade, Throwable error, int statusCode, - String message, String uuid, String code, String errors) { - - Response response = exceptionFacade.toResponse(error); - assertThat(response).isNotNull(); - assertThat(response.getStatus()).isEqualTo(statusCode); - - Object entity = response.getEntity(); - assertThat(entity).isInstanceOf(String.class); - String result = (String) entity; - - try { - Map valueMap = exceptionFacade.getMapper().readValue(result, Map.class); - String msg = message; - if (msg == null) { - msg = error.getLocalizedMessage(); - } - assertThat(valueMap.get(RestServiceExceptionFacade.KEY_MESSAGE)).isEqualTo(msg); - if ((statusCode == 403) && (!exceptionFacade.isExposeInternalErrorDetails())) { - assertThat(result).doesNotContain(error.getMessage()); - } - assertThat(valueMap.get(RestServiceExceptionFacade.KEY_CODE)).isEqualTo(code); - String actualUuid = (String) valueMap.get(RestServiceExceptionFacade.KEY_UUID); - if (UUID_ANY.equals(uuid)) { - if (actualUuid == null) { - fail("UUID expected but not found in response: " + result); - } - } else { - assertThat(actualUuid).isEqualTo(uuid); - } - - Map> errorsMap = - (Map>) valueMap.get(RestServiceExceptionFacade.KEY_ERRORS); - - if (errors == null) { - if (errorsMap != null) { - fail("Errors do not expected but found in response: " + result); - } else { - assertThat(errorsMap).isEqualTo(errors); - } - } else { - if (errorsMap != null) { - assertThat(errorsMap.toString()).isEqualTo(errors); - } else { - fail("Errors expected but not found in response: " + result); - } - - } - - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - return result; - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testJaxrsInternalServerException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String internalMessage = "The HTTP request is invalid"; - int statusCode = 500; - InternalServerErrorException error = new InternalServerErrorException(internalMessage); - String expectedMessage = new TechnicalErrorUserException(error).getLocalizedMessage(); - checkFacade(exceptionFacade, error, statusCode, expectedMessage, UUID_ANY, CODE_TECHNICAL_ERROR); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception. - */ - @Test - public void testJaxrsBadRequestException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String message = "The HTTP request is invalid"; - Throwable error = new BadRequestException(message); - checkFacade(exceptionFacade, error, 400, message, UUID_ANY, "400"); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with a {@link ValidationException}. - */ - @Test - public void testValidationException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String message = "Validation failed!"; - Throwable error = new ValidationException(message); - checkFacade(exceptionFacade, error, 400, message, UUID_ANY, ValidationErrorUserException.CODE); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testJaxrsNotFoundException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String internalMessage = "Either the service URL is wrong or the requested resource does not exist"; - checkFacade(exceptionFacade, new NotFoundException(internalMessage), 404, internalMessage, UUID_ANY, "404"); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testTechnicalJavaRuntimeServerException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String secretMessage = "Internal server error occurred"; - IllegalArgumentException error = new IllegalArgumentException(secretMessage); - String expectedMessage = new TechnicalErrorUserException(error).getLocalizedMessage(); - checkFacade(exceptionFacade, error, 500, expectedMessage, UUID_ANY, CODE_TECHNICAL_ERROR); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testTechnicalCustomRuntimeServerException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - String message = "Internal server error occurred"; - IllegalCaseException error = new IllegalCaseException(message); - String expectedMessage = new TechnicalErrorUserException(error).getLocalizedMessage(); - checkFacade(exceptionFacade, error, 500, expectedMessage, error.getUuid().toString(), CODE_TECHNICAL_ERROR); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testTechnicalCustomRuntimeServerExceptionExposed() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - exceptionFacade.setExposeInternalErrorDetails(true); - String message = "Internal server error occurred"; - IllegalCaseException error = new IllegalCaseException(message); - String expectedMessage = - "TechnicalErrorUserException: An unexpected error has occurred! We apologize any inconvenience. Please try again later." - + StringUtil.LINE_SEPARATOR + error.getClass().getSimpleName() + ": " + error.getLocalizedMessage(); - checkFacade(exceptionFacade, error, 500, expectedMessage, error.getUuid().toString(), CODE_TECHNICAL_ERROR); - } - - /** - * Tests {@link RestServiceExceptionFacade#toResponse(Throwable)} with bad request technical exception including - * subclasses. - */ - @Test - public void testBusinessException() { - - RestServiceExceptionFacade exceptionFacade = getExceptionFacade(); - ObjectNotFoundUserException error = new ObjectNotFoundUserException(4711L); - checkFacade(exceptionFacade, error, 400, null, error.getUuid().toString(), "NotFound"); - } -} diff --git a/oasp4j-modules/oasp4j-security/.checkstyle b/oasp4j-modules/oasp4j-security/.checkstyle deleted file mode 100644 index b6203b021..000000000 --- a/oasp4j-modules/oasp4j-security/.checkstyle +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/oasp4j-modules/oasp4j-security/pom.xml b/oasp4j-modules/oasp4j-security/pom.xml deleted file mode 100644 index 7c4fd294c..000000000 --- a/oasp4j-modules/oasp4j-security/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-security - ${oasp4j.version} - jar - ${project.artifactId} - Security Module of the Open Application Standard Platform for Java (OASP4J). - - - - - - org.springframework - spring-web - - - javax.servlet - javax.servlet-api - provided - - - - - org.springframework.security - spring-security-config - - - org.springframework.security - spring-security-web - - - - - javax.inject - javax.inject - - - javax.annotation - javax.annotation-api - - - - - com.fasterxml.jackson.core - jackson-databind - - - - - - io.oasp.java.modules - oasp4j-test - test - - - ${project.groupId} - oasp4j-logging - test - - - com.google.guava - guava - test - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControl.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControl.java deleted file mode 100644 index 3156cfeac..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControl.java +++ /dev/null @@ -1,104 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import java.io.Serializable; -import java.util.Objects; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlID; -import javax.xml.bind.annotation.XmlSchemaType; -import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; - -/** - * This is the abstract base class for a node of the {@link AccessControlSchema} that represents a tree of - * {@link AccessControlGroup}s and {@link AccessControlPermission}s. If a {@link java.security.Principal} "has" a - * {@link AccessControl} he also "has" all {@link AccessControl}s with according permissions in the spanned sub-tree. - * - * @author hohwille - */ -@XmlAccessorType(XmlAccessType.FIELD) -public abstract class AccessControl implements Serializable { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getName() */ - @XmlID - @XmlAttribute(name = "id", required = true) - @XmlJavaTypeAdapter(CollapsedStringAdapter.class) - @XmlSchemaType(name = "NCName") - private String id; - - /** - * The constructor. - */ - public AccessControl() { - - super(); - } - - /** - * The constructor. - * - * @param id the {@link #getId() ID}. - */ - public AccessControl(String id) { - - super(); - this.id = id; - } - - /** - * @return the unique identifier of this {@link AccessControl}. Has to be unique for all {@link AccessControl} in a - * {@link AccessControlSchema}. - */ - public String getId() { - - return this.id; - } - - /** - * @param id the new {@link #getId() id}. - */ - public void setId(String id) { - - this.id = id; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = 1; - result = prime * result + ((this.id == null) ? 0 : this.id.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AccessControl other = (AccessControl) obj; - if (!Objects.equals(this.id, other.id)) { - return false; - } - return true; - } - - @Override - public String toString() { - - return this.id; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlGroup.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlGroup.java deleted file mode 100644 index 77ee5c31a..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlGroup.java +++ /dev/null @@ -1,161 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlIDREF; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlSchemaType; - -/** - * A {@link AccessControlGroup} represents a collection of {@link AccessControlPermission permissions}. A security - * administrator assigns a {@link java.security.Principal user} to a {@link AccessControlGroup group} to grant him the - * {@link AccessControlPermission permissions} of that {@link AccessControlGroup group}.
- * Please note that a role is a special form of a {@link AccessControlGroup group} that also represents a - * strategic function. Therefore not every {@link AccessControlGroup group} is a role. Often a user can only have one - * role or can only act under one role at a time. Unfortunately these terms are often mixed up what is causing - * confusion. - * - * @author hohwille - */ -@XmlRootElement(name = "group") -public class AccessControlGroup extends AccessControl { // implements java.security.acl.Group { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** @see #getInherits() */ - @XmlIDREF - @XmlElementWrapper(name = "inherits") - @XmlElement(name = "group-ref") - private List inherits; - - /** @see #getPermissions() */ - @XmlElementWrapper(name = "permissions") - @XmlElement(name = "permission") - private List permissions; - - /** @see #getType() */ - @XmlAttribute(name = "type", required = false) - @XmlSchemaType(name = "string") - private String type; - - /** - * The constructor. - */ - public AccessControlGroup() { - - super(); - } - - /** - * The constructor. - * - * @param id the {@link #getId() ID}. - */ - public AccessControlGroup(String id) { - - super(id); - } - - /** - * @return the type of this group. E.g. "role", "department", "use-case-group", etc. You can use this for your own - * purpose. - */ - public String getType() { - - if (this.type == null) { - return ""; - } - return this.type; - } - - /** - * @param type the type to set - */ - public void setType(String type) { - - this.type = type; - } - - /** - * @return inherits - */ - public List getInherits() { - - if (this.inherits == null) { - this.inherits = new ArrayList<>(); - } - return this.inherits; - } - - /** - * @param inherits the inherits to set - */ - public void setInherits(List inherits) { - - this.inherits = inherits; - } - - /** - * @return the {@link List} of {@link AccessControlPermission}s. - */ - public List getPermissions() { - - if (this.permissions == null) { - this.permissions = new ArrayList<>(); - } - return this.permissions; - } - - /** - * @param permissions the new {@link #getPermissions() permissions}. - */ - public void setPermissions(List permissions) { - - this.permissions = permissions; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - // prevent infinity loops or other sick effects - // result = prime * result + ((this.inherits == null) ? 0 : this.inherits.hashCode()); - result = prime * result + ((this.permissions == null) ? 0 : this.permissions.hashCode()); - result = prime * result + ((this.type == null) ? 0 : this.type.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AccessControlGroup other = (AccessControlGroup) obj; - // prevent infinity loops or other sick effects... - // if (!Objects.equal(this.inherits, other.inherits)) { - // return false; - // } - if (!Objects.equals(this.permissions, other.permissions)) { - return false; - } - if (!Objects.equals(this.type, other.type)) { - return false; - } - return true; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlPermission.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlPermission.java deleted file mode 100644 index 463846eaa..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlPermission.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import javax.xml.bind.annotation.XmlRootElement; - -/** - * A {@link AccessControlPermission} represents an atomic permission of the application. Each operation (use-case) - * should have its own {@link AccessControlPermission permission}. These operations are secured referencing the - * {@link #getId() ID} of the {@link AccessControlPermission permission}. We do this by annotating the operation method - * with {@link javax.annotation.security.RolesAllowed} (from JSR 250). Please do not get confused by the name - * {@link javax.annotation.security.RolesAllowed} as we are not assigning roles (see also {@link AccessControlGroup}) - * but {@link AccessControlPermission permissions} instead. We want to use Java standards (such as - * {@link javax.annotation.security.RolesAllowed}) where suitable but assigning the allowed roles to a method would end - * up in unmaintainable system configurations if your application reaches a certain complexity.
- *
- * If a user is logged in and wants to invoke the operation he needs to own the required permission. Therefore his - * {@link AccessControlGroup}s (resp. roles) have to contain the {@link AccessControlPermission permission} - * {@link AccessControlGroup#getPermissions() directly} or {@link AccessControlGroup#getInherits() indirectly}.
- * In order to avoid naming clashes you should use the name of the application component as prefix of the permission. - * - * @author hohwille - */ -@XmlRootElement(name = "permission") -public class AccessControlPermission extends AccessControl { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AccessControlPermission() { - - super(); - } - - /** - * The constructor. - * - * @param id the {@link #getId() ID}. - */ - public AccessControlPermission(String id) { - - super(id); - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlProvider.java deleted file mode 100644 index 01e43be9b..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlProvider.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import java.util.Set; - -/** - * This is the interface for a provider of {@link AccessControl}s. It allows to - * {@link #collectAccessControlIds(String, Set) collect} all {@link AccessControl}s for an ID of a {@link AccessControl} - * (typically a {@link AccessControlGroup} or role). This is used to expand the groups provided by the access-manager - * (authentication and identity-management) to the full set of {@link AccessControlPermission permissions} of the - * {@link java.security.Principal user}.
- * The actual authorization can then check individual permissions of the user by simply checking for - * {@link Set#contains(Object) contains} in the collected {@link Set}, what is very fast as security checks happen - * frequently. - * - * @see PrincipalAccessControlProvider - * - * @author hohwille - */ -public interface AccessControlProvider { - - /** - * @param id is the {@link AccessControl#getId() ID} of the requested {@link AccessControl}. - * @return the requested {@link AccessControl} or {@code null} if not found. - */ - AccessControl getAccessControl(String id); - - /** - * This method collects the {@link AccessControl#getId() IDs} of all {@link AccessControlPermission}s (or more - * precisely of all {@link AccessControl}s) contained in the {@link AccessControl} {@link AccessControl#getId() - * identified} by the given groupId. - * - * @see #collectAccessControls(String, Set) - * - * @param id is the {@link AccessControl#getId() ID} of the {@link AccessControl} (typically an - * {@link AccessControlGroup}) to collect. - * @param permissions is the {@link Set} where to {@link Set#add(Object) add} the collected - * {@link AccessControl#getId() IDs}. This will include the given groupId. - * @return {@code true} if the given groupId has been found, {@code false} otherwise. - */ - boolean collectAccessControlIds(String id, Set permissions); - - /** - * This method collects the {@link AccessControl}s contained in the {@link AccessControl} - * {@link AccessControl#getId() identified} by the given groupId. - * - * @param id is the {@link AccessControl#getId() ID} of the {@link AccessControl} (typically an - * {@link AccessControlGroup}) to collect. - * @param permissions is the {@link Set} where to {@link Set#add(Object) add} the collected {@link AccessControl}s. - * This will include the {@link AccessControl} {@link AccessControl#getId() identified} by the given - * groupId. - * @return {@code true} if the given groupId has been found, {@code false} otherwise. - */ - boolean collectAccessControls(String id, Set permissions); - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlSchema.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlSchema.java deleted file mode 100644 index 31be3d7d6..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/AccessControlSchema.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - -/** - * This class represents the security configuration for the mapping of {@link AccessControlGroup}s to - * {@link AccessControlPermission}s. Everything is properly annotated for JAXB (de)serialization from/to XML. - * - * @author hohwille - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "access-control-schema") -public class AccessControlSchema { - - /** @see #getGroups() */ - @XmlElement(name = "group") - private List groups; - - /** - * The constructor. - */ - public AccessControlSchema() { - - super(); - } - - /** - * @return the {@link List} of {@link AccessControlGroup}s contained in this {@link AccessControlSchema}. - */ - public List getGroups() { - - if (this.groups == null) { - this.groups = new ArrayList<>(); - } - return this.groups; - } - - /** - * @param groups the new {@link #getGroups() groups}. - */ - public void setGroups(List groups) { - - this.groups = groups; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = 1; - result = prime * result + ((this.groups == null) ? 0 : this.groups.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AccessControlSchema other = (AccessControlSchema) obj; - if (!Objects.equals(this.groups, other.groups)) { - return false; - } - return true; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/PrincipalAccessControlProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/PrincipalAccessControlProvider.java deleted file mode 100644 index 2f4b0b403..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/accesscontrol/PrincipalAccessControlProvider.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.oasp.module.security.common.api.accesscontrol; - -import java.security.Principal; -import java.util.Collection; - -/** - * This is the interface for a provide that allows to {@link #getAccessControlIds(Principal) get the permission groups} for a - * {@link Principal}. - * - * @param

is the generic type of the {@link Principal} representing the user or subject. - * - * @author hohwille - */ -public interface PrincipalAccessControlProvider

{ - - /** - * @param principal is the {@link Principal} (user). - * @return the {@link Collection} of {@link AccessControl#getId() IDs} with the groups of the given {@link Principal}. - */ - Collection getAccessControlIds(P principal); - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/exception/InvalidConfigurationException.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/exception/InvalidConfigurationException.java deleted file mode 100644 index 0e6a07f8d..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/api/exception/InvalidConfigurationException.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.oasp.module.security.common.api.exception; - -/** - * Signals an exception during reading the security configuration - * - * @author mbrunnli - */ -public class InvalidConfigurationException extends RuntimeException { - - /** - * Default serial version UID - */ - private static final long serialVersionUID = 1L; - - /** - * Creates a new {@link InvalidConfigurationException} with the given message - * - * @param message error message - */ - public InvalidConfigurationException(String message) { - - super(message); - } - - /** - * Creates a new {@link InvalidConfigurationException} with the given message and the given cause - * - * @param message error message - * @param ex cause of the created exception - */ - public InvalidConfigurationException(String message, Throwable ex) { - - super(message, ex); - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlBasedAuthenticationProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlBasedAuthenticationProvider.java deleted file mode 100644 index 9c0ede3c8..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlBasedAuthenticationProvider.java +++ /dev/null @@ -1,159 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControl; -import io.oasp.module.security.common.api.accesscontrol.AccessControlProvider; -import io.oasp.module.security.common.api.accesscontrol.PrincipalAccessControlProvider; - -import java.security.Principal; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Inject; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -/** - * This is an implementation of {@link AbstractUserDetailsAuthenticationProvider} based on - * {@link PrincipalAccessControlProvider} and {@link AccessControlProvider}. - * - * @param is the generic type of the {@link UserDetails} implementation used to bridge with spring-security. - * @param

is the generic type of the {@link Principal} for internal user representation to bridge with - * {@link PrincipalAccessControlProvider}. - * - * @author hohwille - */ -public abstract class AbstractAccessControlBasedAuthenticationProvider - extends AbstractUserDetailsAuthenticationProvider { - - /** The {@link Logger} instance. */ - private static final Logger LOG = LoggerFactory.getLogger(AbstractAccessControlBasedAuthenticationProvider.class); - - private PrincipalAccessControlProvider

principalAccessControlProvider; - - private AccessControlProvider accessControlProvider; - - /** - * The constructor. - */ - public AbstractAccessControlBasedAuthenticationProvider() { - - } - - /** - * @param principalAccessControlProvider the {@link PrincipalAccessControlProvider} to {@link Inject}. - */ - @Inject - public void setPrincipalAccessControlProvider(PrincipalAccessControlProvider

principalAccessControlProvider) { - - this.principalAccessControlProvider = principalAccessControlProvider; - } - - /** - * @param accessControlProvider the {@link AccessControlProvider} to {@link Inject}. - */ - @Inject - public void setAccessControlProvider(AccessControlProvider accessControlProvider) { - - this.accessControlProvider = accessControlProvider; - } - - /** - * Here the actual authentication has to be implemented.
- *
- * - */ - @Override - protected void additionalAuthenticationChecks(UserDetails userDetails, - UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { - - // default implementation authentications via servlet API (container managed) - ServletRequestAttributes currentRequestAttributes = - (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); - - HttpServletRequest request = currentRequestAttributes.getRequest(); - String login = authentication.getName(); - String password = null; - Object credentials = authentication.getCredentials(); - if (credentials != null) { - password = credentials.toString(); - } - try { - request.login(login, password); - } catch (ServletException e) { - LOG.warn("Authentication failed: {}", e.toString()); - throw new BadCredentialsException("Authentication failed.", e); - } - authentication.setDetails(userDetails); - } - - /** - * Creates an instance of {@link UserDetails} that represent the user with the given username. - * - * @param username is the login of the user to create. - * @param password the password of the user. - * @param principal is the internal {@link Principal} that has been provided by - * {@link #retrievePrincipal(String, UsernamePasswordAuthenticationToken)}. - * @param authorities are the {@link GrantedAuthority granted authorities} or in other words the permissions of the - * user. - * @return the new user object. - */ - protected abstract U createUser(String username, String password, P principal, Set authorities); - - /** - * Retrieves the internal {@link Principal} object representing the user. This can be any object implementing - * {@link Principal} and can contain additional user details such as profile data. This object is used to - * {@link PrincipalAccessControlProvider#getAccessControlIds(Principal) retrieve} the (top-level) - * {@link AccessControl}s that have been granted to the user. - * - * @param username is the login of the user. - * @param authentication is the {@link UsernamePasswordAuthenticationToken}. - * @return the {@link Principal}. - */ - protected abstract P retrievePrincipal(String username, UsernamePasswordAuthenticationToken authentication); - - @Override - protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { - - P principal = retrievePrincipal(username, authentication); - if (principal == null) { - LOG.warn("Failed to retrieve user for login {}.", username); - throw new UsernameNotFoundException(username); - } - - // determine granted authorities for spring-security... - Set authorities = new HashSet<>(); - Collection accessControlIds = this.principalAccessControlProvider.getAccessControlIds(principal); - Set accessControlSet = new HashSet<>(); - for (String id : accessControlIds) { - boolean success = this.accessControlProvider.collectAccessControls(id, accessControlSet); - if (!success) { - LOG.warn("Undefined access control {}.", id); - // authorities.add(new SimpleGrantedAuthority(id)); - } - } - for (AccessControl accessControl : accessControlSet) { - authorities.add(new AccessControlGrantedAuthority(accessControl)); - } - - String password = null; - Object credentials = authentication.getCredentials(); - if (credentials != null) { - password = credentials.toString(); - } - return createUser(username, password, principal, authorities); - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlProvider.java deleted file mode 100644 index 4930f6fc2..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AbstractAccessControlProvider.java +++ /dev/null @@ -1,197 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControl; -import io.oasp.module.security.common.api.accesscontrol.AccessControlGroup; -import io.oasp.module.security.common.api.accesscontrol.AccessControlPermission; -import io.oasp.module.security.common.api.accesscontrol.AccessControlProvider; -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This is the abstract base implementation of {@link AccessControlProvider}.
- * ATTENTION:
- * You need to call {@link #initialize(AccessControlSchema)} from the derived implementation. - * - * @author hohwille - */ -public abstract class AbstractAccessControlProvider implements AccessControlProvider { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(AbstractAccessControlProvider.class); - - /** @see #getAccessControl(String) */ - private final Map id2nodeMap; - - /** - * The constructor. - */ - public AbstractAccessControlProvider() { - - super(); - this.id2nodeMap = new HashMap<>(); - } - - /** - * Performs the required initialization of this class. - * - * @param config is the {@link AccessControlSchema}. - */ - protected void initialize(AccessControlSchema config) { - - LOG.debug("Initializing."); - List groups = config.getGroups(); - if (groups.size() == 0) { - throw new IllegalStateException("AccessControlSchema is empty - please configure at least one group!"); - } - Set toplevelGroups = new HashSet<>(groups); - for (AccessControlGroup group : groups) { - collectAccessControls(group, toplevelGroups); - checkForCyclicDependencies(group, new HashSet()); - } - } - - /** - * Checks that the given {@link AccessControlGroup} has no cyclic {@link AccessControlGroup#getInherits() inheritance - * graph}. - * - * @param group is the {@link AccessControlGroup} to check. - * @param visitedGroups is where the {@link AccessControlGroup} are collected to detect cycles. - */ - protected void checkForCyclicDependencies(AccessControlGroup group, Set visitedGroups) { - - boolean added = visitedGroups.add(group); - if (!added) { - // mmm NodeCycleException would be very helpful here... - throw new IllegalStateException("Cyclic inheritance of access control groups detected for " + group); - } - for (AccessControlGroup inheritedGroup : group.getInherits()) { - checkForCyclicDependencies(inheritedGroup, visitedGroups); - } - } - - /** - * Called from {@link #initialize(AccessControlSchema)} to collect all {@link AccessControl}s recursively. - * - * @param group the {@link AccessControlGroup} to traverse. - * @param toplevelGroups is the {@link Set} of all {@link AccessControlGroup}s from - * {@link AccessControlSchema#getGroups()}. - */ - protected void collectAccessControls(AccessControlGroup group, Set toplevelGroups) { - - // TODO hohwille Java HashMap buggy??? - // if (!toplevelGroups.contains(group)) { - // throw new IllegalStateException("Invalid group not declared as top-level group in schema: " + group); - // } - AccessControl old = this.id2nodeMap.put(group.getId(), group); - if (old != null) { - LOG.debug("Already visited access control group {}", group); - if (old != group) { - throw new IllegalStateException("Invalid security configuration: duplicate groups with id " + group.getId() - + "!"); - } - // group has already been visited, stop recursion... - return; - } else { - LOG.debug("Registered access control group {}", group); - } - for (AccessControlPermission permission : group.getPermissions()) { - old = this.id2nodeMap.put(permission.getId(), permission); - if (old != null) { - // throw new IllegalStateException("Invalid security configuration: duplicate permission with id " - // + permission.getId() + "!"); - LOG.warn("Security configuration contains duplicate permission with id {}.", permission.getId()); - } else { - LOG.debug("Registered access control permission {}", permission); - } - } - for (AccessControlGroup inheritedGroup : group.getInherits()) { - collectAccessControls(inheritedGroup, toplevelGroups); - } - } - - @Override - public AccessControl getAccessControl(String nodeId) { - - return this.id2nodeMap.get(nodeId); - } - - @Override - public boolean collectAccessControlIds(String groupId, Set permissions) { - - AccessControl node = getAccessControl(groupId); - if (node instanceof AccessControlGroup) { - collectPermissionIds((AccessControlGroup) node, permissions); - } else { - // node does not exist or is a flat AccessControlPermission - permissions.add(groupId); - } - return (node != null); - } - - /** - * Recursive implementation of {@link #collectAccessControlIds(String, Set)} for {@link AccessControlGroup}s. - * - * @param group is the {@link AccessControlGroup} to traverse. - * @param permissions is the {@link Set} used to collect. - */ - public void collectPermissionIds(AccessControlGroup group, Set permissions) { - - boolean added = permissions.add(group.getId()); - if (!added) { - // we have already visited this node, stop recursion... - return; - } - for (AccessControlPermission permission : group.getPermissions()) { - permissions.add(permission.getId()); - } - for (AccessControlGroup inheritedGroup : group.getInherits()) { - collectPermissionIds(inheritedGroup, permissions); - } - } - - @Override - public boolean collectAccessControls(String groupId, Set permissions) { - - AccessControl node = getAccessControl(groupId); - if (node == null) { - return false; - } - if (node instanceof AccessControlGroup) { - collectPermissionNodes((AccessControlGroup) node, permissions); - } else { - // node is a flat AccessControlPermission - permissions.add(node); - } - return true; - } - - /** - * Recursive implementation of {@link #collectAccessControls(String, Set)} for {@link AccessControlGroup}s. - * - * @param group is the {@link AccessControlGroup} to traverse. - * @param permissions is the {@link Set} used to collect. - */ - public void collectPermissionNodes(AccessControlGroup group, Set permissions) { - - boolean added = permissions.add(group); - if (!added) { - // we have already visited this node, stop recursion... - return; - } - for (AccessControlPermission permission : group.getPermissions()) { - permissions.add(permission); - } - for (AccessControlGroup inheritedGroup : group.getInherits()) { - collectPermissionNodes(inheritedGroup, permissions); - } - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlGrantedAuthority.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlGrantedAuthority.java deleted file mode 100644 index 708f52603..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlGrantedAuthority.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControl; - -import java.util.Objects; - -import org.springframework.security.core.GrantedAuthority; - -/** - * Implementation of {@link GrantedAuthority} for a {@link AccessControl}. - * - * @author hohwille - */ -public class AccessControlGrantedAuthority implements GrantedAuthority { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - private final AccessControl accessControl; - - /** - * The constructor. - * - * @param accessControl the {@link #getAccessControl() access control}. - */ - public AccessControlGrantedAuthority(AccessControl accessControl) { - - super(); - Objects.requireNonNull(accessControl, AccessControl.class.getSimpleName()); - this.accessControl = accessControl; - } - - /** - * @return the contained {@link AccessControl}. - */ - public AccessControl getAccessControl() { - - return this.accessControl; - } - - @Override - public String getAuthority() { - - return this.accessControl.getId(); - } - - @Override - public String toString() { - - return getAuthority(); - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaMapper.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaMapper.java deleted file mode 100644 index 5b545d199..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; - -import java.io.InputStream; -import java.io.OutputStream; - -/** - * This is the interface to {@link #read(InputStream)} and {@link #write(AccessControlSchema, OutputStream)} the - * {@link AccessControlSchema}. - * - * @author hohwille - */ -public interface AccessControlSchemaMapper { - - /** - * Reads the {@link AccessControlSchema} from the given {@link InputStream}. - * - * @param in is the {@link InputStream} with {@link AccessControlSchema} to read. Has to be - * {@link InputStream#close() closed} by the caller of this method who created the stream. - * @return the {@link AccessControlSchema} represented by the given input. - */ - AccessControlSchema read(InputStream in); - - /** - * Writes the given {@link AccessControlSchema} to the given {@link OutputStream}. - * - * @param conf is the {@link AccessControlSchema} to write. - * @param out is the {@link OutputStream} where to write the {@link AccessControlSchema} to. Has to be - * {@link OutputStream#close() closed} by the caller of this method who created the stream. - */ - void write(AccessControlSchema conf, OutputStream out); - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaProvider.java deleted file mode 100644 index 685a6fff0..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/AccessControlSchemaProvider.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; - -/** - * This is the interface to {@link #loadSchema() load} the {@link AccessControlSchema} from an arbitrary source. The - * default implementation will load it from an XML file. You could create your own implementation to read from database - * or wherever if default is not suitable. - * - * @author hohwille - */ -public interface AccessControlSchemaProvider { - - /** - * @return the loaded {@link AccessControlSchema}. May not be {@code null}. - */ - AccessControlSchema loadSchema(); - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/PrincipalGroupProviderGroupImpl.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/PrincipalGroupProviderGroupImpl.java deleted file mode 100644 index 0eea16490..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/PrincipalGroupProviderGroupImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.PrincipalAccessControlProvider; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; - -/** - * This is an implementation of {@link PrincipalAccessControlProvider} based on {@link Group}. Due to the confusing API of - * {@link Group} that mixes a {@link Principal} with permissions and permission groups it is not commonly used even - * though it is available in the Java standard edition. - * - * @author hohwille - */ -public class PrincipalGroupProviderGroupImpl implements PrincipalAccessControlProvider { - - /** - * The constructor. - */ - public PrincipalGroupProviderGroupImpl() { - - super(); - } - - @Override - public Collection getAccessControlIds(Group principal) { - - Set groupSet = new HashSet<>(); - collectGroups(principal, groupSet); - return groupSet; - } - - /** - * Called from {@link #getAccessControlIds(Group)} to recursively collect the groups. - * - * @param group is the {@link Group} to traverse. - * @param groupSet is the {@link Set} where to add the principal names. - */ - protected void collectGroups(Group group, Set groupSet) { - - Enumeration members = group.members(); - while (members.hasMoreElements()) { - Principal member = members.nextElement(); - String name = member.getName(); - boolean added = groupSet.add(name); - if (added && (member instanceof Group)) { - collectGroups((Group) member, groupSet); - } - } - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/SimpleAccessControlBasedAuthenticationProvider.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/SimpleAccessControlBasedAuthenticationProvider.java deleted file mode 100644 index c00e6731a..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/base/accesscontrol/SimpleAccessControlBasedAuthenticationProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.oasp.module.security.common.base.accesscontrol; - -import java.security.Principal; -import java.util.Set; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; - -/** - * This is a simple implementation of {@link AbstractAccessControlBasedAuthenticationProvider}. - * - * @author hohwille - */ -public class SimpleAccessControlBasedAuthenticationProvider extends - AbstractAccessControlBasedAuthenticationProvider { - - /** - * The constructor. - */ - public SimpleAccessControlBasedAuthenticationProvider() { - - super(); - } - - @Override - protected User createUser(String username, String password, Principal principal, Set authorities) { - - User user = new User(username, password, authorities); - return user; - } - - @Override - protected Principal retrievePrincipal(String username, UsernamePasswordAuthenticationToken authentication) { - - return authentication; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlProviderImpl.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlProviderImpl.java deleted file mode 100644 index 119184dd6..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlProviderImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.oasp.module.security.common.impl.accesscontrol; - -import io.oasp.module.security.common.base.accesscontrol.AbstractAccessControlProvider; -import io.oasp.module.security.common.base.accesscontrol.AccessControlSchemaProvider; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; - -/** - * This is the default implementation of {@link io.oasp.module.security.common.api.accesscontrol.AccessControlProvider}. - * - * @author hohwille - */ -public class AccessControlProviderImpl extends AbstractAccessControlProvider { - - private AccessControlSchemaProvider accessControlSchemaProvider; - - /** - * The constructor. - */ - public AccessControlProviderImpl() { - - super(); - } - - /** - * Initializes this class. - */ - @PostConstruct - public void initialize() { - - if (this.accessControlSchemaProvider == null) { - this.accessControlSchemaProvider = new AccessControlSchemaProviderImpl(); - } - initialize(this.accessControlSchemaProvider.loadSchema()); - } - - /** - * @return accessControlSchemaProvider - */ - public AccessControlSchemaProvider getAccessControlSchemaProvider() { - - return this.accessControlSchemaProvider; - } - - /** - * @param accessControlSchemaProvider the {@link AccessControlSchemaProvider} to {@link Inject}. - */ - @Inject - public void setAccessControlSchemaProvider(AccessControlSchemaProvider accessControlSchemaProvider) { - - this.accessControlSchemaProvider = accessControlSchemaProvider; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaProviderImpl.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaProviderImpl.java deleted file mode 100644 index ce9c2fa82..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaProviderImpl.java +++ /dev/null @@ -1,108 +0,0 @@ -package io.oasp.module.security.common.impl.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; -import io.oasp.module.security.common.base.accesscontrol.AccessControlSchemaMapper; -import io.oasp.module.security.common.base.accesscontrol.AccessControlSchemaProvider; - -import java.io.InputStream; - -import javax.annotation.PostConstruct; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -/** - * This is the default implementation of {@link AccessControlSchemaProvider}. - * - * @author hohwille - */ -public class AccessControlSchemaProviderImpl implements AccessControlSchemaProvider { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(AccessControlSchemaProviderImpl.class); - - private Resource accessControlSchema; - - private AccessControlSchemaMapper accessControlSchemaMapper; - - private boolean initialized; - - /** - * The constructor. - */ - public AccessControlSchemaProviderImpl() { - - super(); - this.initialized = false; - } - - /** - * Initializes this class. - */ - @PostConstruct - public void initialize() { - - if (this.initialized) { - return; - } - LOG.debug("Initializing."); - if (this.accessControlSchemaMapper == null) { - this.accessControlSchemaMapper = new AccessControlSchemaXmlMapper(); - } - if (this.accessControlSchema == null) { - // this.accessControlSchema = new - // ClassPathResource(ApplicationConfigurationConstants.SECURITY_ACCESS_CONTROL_SCHEMA); - this.accessControlSchema = new ClassPathResource("config/app/security/access-control-schema.xml"); - } - this.initialized = true; - } - - @Override - public AccessControlSchema loadSchema() { - - initialize(); - LOG.debug("Reading access control schema from {}", this.accessControlSchema); - try (InputStream inputStream = this.accessControlSchema.getInputStream()) { - AccessControlSchema schema = this.accessControlSchemaMapper.read(inputStream); - LOG.debug("Reading access control schema completed successfully."); - return schema; - } catch (Exception e) { - throw new IllegalStateException("Failed to load access control schema from " + this.accessControlSchema, e); - } - } - - /** - * @return the {@link AccessControlSchemaMapper}. - */ - public AccessControlSchemaMapper getAccessControlSchemaMapper() { - - return this.accessControlSchemaMapper; - } - - /** - * @param accessControlSchemaMapper the {@link AccessControlSchemaMapper} to use. - */ - public void setAccessControlSchemaMapper(AccessControlSchemaMapper accessControlSchemaMapper) { - - this.accessControlSchemaMapper = accessControlSchemaMapper; - } - - /** - * @return accessControlSchema - */ - public Resource getAccessControlSchema() { - - return this.accessControlSchema; - } - - /** - * @param accessControlSchema the {@link Resource} pointing to the XML configuration of the access control schema. - */ - public void setAccessControlSchema(Resource accessControlSchema) { - - this.accessControlSchema = accessControlSchema; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXmlMapper.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXmlMapper.java deleted file mode 100644 index 1ada0bbb3..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXmlMapper.java +++ /dev/null @@ -1,153 +0,0 @@ -package io.oasp.module.security.common.impl.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; -import io.oasp.module.security.common.base.accesscontrol.AccessControlSchemaMapper; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.SchemaOutputResolver; -import javax.xml.bind.Unmarshaller; -import javax.xml.bind.ValidationEvent; -import javax.xml.bind.ValidationEventHandler; -import javax.xml.transform.Result; -import javax.xml.transform.stream.StreamResult; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is a simple wrapper for {@link #read(InputStream) reading} and - * {@link #write(AccessControlSchema, OutputStream) writing} the {@link AccessControlSchema} from/to XML. - * - * @author hohwille - */ -public class AccessControlSchemaXmlMapper implements AccessControlSchemaMapper { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(AccessControlSchemaXmlMapper.class); - - private JAXBContext jaxbContext; - - /** - * The constructor. - */ - public AccessControlSchemaXmlMapper() { - - super(); - try { - this.jaxbContext = JAXBContext.newInstance(AccessControlSchema.class); - } catch (JAXBException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void write(AccessControlSchema conf, OutputStream out) { - - try { - Marshaller marshaller = this.jaxbContext.createMarshaller(); - marshaller.marshal(conf, out); - } catch (JAXBException e) { - throw new IllegalStateException("Marshalling XML failed!", e); - } - } - - @Override - public AccessControlSchema read(InputStream in) { - - try { - Unmarshaller unmarshaller = this.jaxbContext.createUnmarshaller(); - ValidationEventHandler handler = new ValidationEventHandlerImpl(); - unmarshaller.setEventHandler(handler); - return (AccessControlSchema) unmarshaller.unmarshal(in); - } catch (JAXBException e) { - throw new IllegalStateException("Unmarshalling XML failed!", e); - } - } - - /** - * Generates the XSD (XML Schema Definition) to the given {@link File}. - * - * @param outFile is the {@link File} to write to. - */ - public void writeXsd(File outFile) { - - File folder = outFile.getParentFile(); - if (!folder.isDirectory()) { - boolean success = folder.mkdirs(); - if (!success) { - throw new IllegalStateException("Failed to create folder " + folder); - } - } - try (FileOutputStream fos = new FileOutputStream(outFile)) { - writeXsd(fos); - } catch (Exception e) { - throw new IllegalStateException("Failed to generate and write the XSD schema to " + outFile + "!", e); - } - } - - /** - * Generates the XSD (XML Schema Definition) to the given {@link OutputStream}. - * - * @param out is the {@link OutputStream} to write to. - */ - public void writeXsd(final OutputStream out) { - - SchemaOutputResolver sor = new SchemaOutputResolver() { - - @Override - public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException { - - StreamResult streamResult = new StreamResult(out); - streamResult.setSystemId(suggestedFileName); - return streamResult; - } - - }; - try { - this.jaxbContext.generateSchema(sor); - } catch (IOException e) { - throw new IllegalStateException("Failed to generate and write the XSD schema!", e); - } - } - - /** - * Custom implementation of {@link ValidationEventHandler}. - */ - protected static class ValidationEventHandlerImpl implements ValidationEventHandler { - - /** - * The constructor. - */ - public ValidationEventHandlerImpl() { - - super(); - } - - @Override - public boolean handleEvent(ValidationEvent event) { - - if (event != null) { - switch (event.getSeverity()) { - case ValidationEvent.ERROR: - case ValidationEvent.FATAL_ERROR: - throw new IllegalArgumentException(event.toString()); - case ValidationEvent.WARNING: - LOG.warn(event.toString()); - break; - default: - LOG.debug(event.toString()); - } - } - return true; - } - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXsdWriter.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXsdWriter.java deleted file mode 100644 index a2079d335..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaXsdWriter.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.oasp.module.security.common.impl.accesscontrol; - -import java.io.File; - -/** - * This is a simple programm to generate (create or update) the XSD for the - * {@link io.oasp.module.security.common.api.accesscontrol.AccessControlSchema}. - * - * @author hohwille - */ -public class AccessControlSchemaXsdWriter extends AccessControlSchemaXmlMapper { - - /** - * The constructor. - */ - public AccessControlSchemaXsdWriter() { - - super(); - } - - /** - * The main method to launch this program. - * - * @param args the command-line arguments (will be ignored). - */ - public static void main(String[] args) { - - AccessControlSchemaXmlMapper mapper = new AccessControlSchemaXmlMapper(); - mapper.writeXsd(new File("src/main/resources/io/oasp/module/security/access-control-schema.xsd")); - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/AuthenticationSuccessHandlerSendingOkHttpStatusCode.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/AuthenticationSuccessHandlerSendingOkHttpStatusCode.java deleted file mode 100644 index 978fdd049..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/AuthenticationSuccessHandlerSendingOkHttpStatusCode.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.oasp.module.security.common.impl.rest; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.springframework.security.core.Authentication; -import org.springframework.security.web.WebAttributes; -import org.springframework.security.web.authentication.AuthenticationSuccessHandler; - -/** - * Sends the OK status code upon successful authentication. - * - * @see JsonUsernamePasswordAuthenticationFilter - * @author Marek Matczak - */ -public class AuthenticationSuccessHandlerSendingOkHttpStatusCode implements AuthenticationSuccessHandler { - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws IOException, ServletException { - - if (response.isCommitted()) { - return; - } - clearAuthenticationAttributes(request); - response.setStatus(HttpServletResponse.SC_OK); - } - - private void clearAuthenticationAttributes(HttpServletRequest request) { - - HttpSession session = request.getSession(false); - if (session == null) { - return; - } - session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/JsonUsernamePasswordAuthenticationFilter.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/JsonUsernamePasswordAuthenticationFilter.java deleted file mode 100644 index 9f2d44e9b..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/JsonUsernamePasswordAuthenticationFilter.java +++ /dev/null @@ -1,218 +0,0 @@ -package io.oasp.module.security.common.impl.rest; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.util.matcher.RequestMatcher; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - *

- * Processes authentication where credentials are sent as a JSON object. - *

- *

- * The JSON object must contain two properties: a username and a password. The default properties' names to use are - * contained in the static fields {@link UsernamePasswordAuthenticationFilter#SPRING_SECURITY_FORM_USERNAME_KEY} and - * {@link UsernamePasswordAuthenticationFilter#SPRING_SECURITY_FORM_PASSWORD_KEY}. The JSON object properties' names can - * also be changed by setting the {@code usernameParameter} and {@code passwordParameter} properties. Assuming the - * default properties' names were not changed, if the credentials user/pass are to be sent, - * the following JSON object is expected: - * - *

- * 
- *     {
- *        "j_username": "user",
- *        "j_password": "pass",
- *    }
- * 
- * 
- *

- *

- * The URL this filter responds to is passed as a constructor parameter. - *

- *

- * This authentication filter is intended for One Page Applications which handle a login page/dialog/pop-up on their - * own. This filter combined with: - *

    - *
  • {@link AuthenticationSuccessHandlerSendingOkHttpStatusCode}
  • - *
  • {@link org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler} created using the - * default constructor (thus leaving the {@code defaultFailureUrl} unset)
  • - *
  • {@link LogoutSuccessHandlerReturningOkHttpStatusCode}
  • - *
- * makes the login/logout API fully RESTful. - *

- * - * @author Marek Matczak - */ -public class JsonUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { - private String usernameParameter = UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY; - - private String passwordParameter = UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY; - - private boolean postOnly = true; - - // REVIEW may-bee (hohwille) We have a centralized and custom-configured object mapper as spring bean. IMHO we should - // inject that instance here. - private ObjectMapper objectMapper = new ObjectMapper(); - - /** - * The constructor. - * - * @param requiresAuthenticationRequestMatcher the {@link RequestMatcher} used to determine if authentication is - * required. Cannot be null. - */ - public JsonUsernamePasswordAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) { - - super(requiresAuthenticationRequestMatcher); - } - - @Override - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) - throws AuthenticationException, IOException, ServletException { - - if (this.postOnly && !request.getMethod().equals("POST")) { - throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); - } - - final UsernameAndPasswordParser usernameAndPasswordParser = new UsernameAndPasswordParser(request); - usernameAndPasswordParser.parse(); - UsernamePasswordAuthenticationToken authRequest = - new UsernamePasswordAuthenticationToken(usernameAndPasswordParser.getTrimmedUsername(), - usernameAndPasswordParser.getPassword()); - // authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); - return getAuthenticationManager().authenticate(authRequest); - } - - /** - * @return Value of usernameParameter - */ - public String getUsernameParameter() { - - return this.usernameParameter; - } - - /** - * @param usernameParameter new value for usernameParameter - */ - public void setUsernameParameter(String usernameParameter) { - - this.usernameParameter = usernameParameter; - } - - /** - * @return Value of passwordParameter - */ - public String getPasswordParameter() { - - return this.passwordParameter; - } - - /** - * @param passwordParameter new value for passwordParameter - */ - public void setPasswordParameter(String passwordParameter) { - - this.passwordParameter = passwordParameter; - } - - /** - * @return value of postOnly - */ - public boolean isPostOnly() { - - return this.postOnly; - } - - /** - * @param postOnly new value for postOnly - */ - public void setPostOnly(boolean postOnly) { - - this.postOnly = postOnly; - } - - private class UsernameAndPasswordParser { - private String username; - - private String password; - - private final HttpServletRequest request; - - private JsonNode credentialsNode; - - private UsernameAndPasswordParser(HttpServletRequest request) { - - this.request = request; - } - - public void parse() { - - parseJsonFromRequestBody(); - if (jsonParsedSuccessfully()) { - extractUsername(); - extractPassword(); - } - } - - private void extractPassword() { - - this.password = extractValueByName(JsonUsernamePasswordAuthenticationFilter.this.passwordParameter); - } - - private void extractUsername() { - - this.username = extractValueByName(JsonUsernamePasswordAuthenticationFilter.this.usernameParameter); - } - - private String extractValueByName(String name) { - - String value = null; - if (this.credentialsNode.has(name)) { - JsonNode node = this.credentialsNode.get(name); - if (node != null) { - value = node.asText(); - } - } - return value; - } - - private boolean jsonParsedSuccessfully() { - - return this.credentialsNode != null; - } - - private void parseJsonFromRequestBody() { - - try { - final ServletServerHttpRequest servletServerHttpRequest = new ServletServerHttpRequest(this.request); - this.credentialsNode = - JsonUsernamePasswordAuthenticationFilter.this.objectMapper.readTree(servletServerHttpRequest.getBody()); - } catch (IOException e) { - // ignoring - } - } - - private String getTrimmedUsername() { - - return this.username == null ? "" : this.username.trim(); - } - - private String getPassword() { - - return this.password == null ? "" : this.password; - } - - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/LogoutSuccessHandlerReturningOkHttpStatusCode.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/LogoutSuccessHandlerReturningOkHttpStatusCode.java deleted file mode 100644 index 68ea3ff9c..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/rest/LogoutSuccessHandlerReturningOkHttpStatusCode.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.oasp.module.security.common.impl.rest; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; - -/** - * Sends the OK status code upon successful logout. - * - * @see JsonUsernamePasswordAuthenticationFilter - * @author Marek Matczak - */ -public class LogoutSuccessHandlerReturningOkHttpStatusCode implements LogoutSuccessHandler { - /** - * Called after a successful logout by the {@link JsonUsernamePasswordAuthenticationFilter}. - */ - @Override - public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException, ServletException { - - if (response.isCommitted()) { - return; - } - response.setStatus(HttpServletResponse.SC_OK); - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/web/RetainAnchorFilter.java b/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/web/RetainAnchorFilter.java deleted file mode 100644 index b5f992aa3..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/java/io/oasp/module/security/common/impl/web/RetainAnchorFilter.java +++ /dev/null @@ -1,190 +0,0 @@ -package io.oasp.module.security.common.impl.web; - -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.springframework.web.filter.GenericFilterBean; - -/** - * Spring Security filter that preserves the URL anchor if the authentication process contains redirects (e.g. if the - * login is performed via CAS or form login). - * - * With standard redirects (default Spring Security behavior), Internet Explorer (6.0 and 8.0) discard the anchor part - * of the URL such that e.g. bookmarking does not work properly. Firefox re-appends the anchor part. - * - * This filter replaces redirects to URLs that match a certain pattern (storeUrlPattern) with a Javascript - * page that stores the URL anchor in a cookie, and replaces redirects to URLs that match another pattern ( - * restoreUrlPattern) with a Javascript page that restores the URL anchor from that cookie. The cookie name - * can be set via the attribute cookieName. - * - * @author mbrunnli (contributed by guidow08 & mpickell) - * @see Forum post of guidow08 - * @see Forum post of mpickell - */ -public class RetainAnchorFilter extends GenericFilterBean { - - private String storeUrlPattern; - - private String restoreUrlPattern; - - private String cookieName; - - /** - * Sets the url pattern for storing anchors. - * - * @param storeUrlPattern url regular expression - */ - public void setStoreUrlPattern(String storeUrlPattern) { - - this.storeUrlPattern = storeUrlPattern; - } - - /** - * Sets the url pattern for restoring anchors. - * - * @param restoreUrlPattern url regular expression - */ - public void setRestoreUrlPattern(String restoreUrlPattern) { - - this.restoreUrlPattern = restoreUrlPattern; - } - - /** - * Sets the cookie name in which the anchor data should be saved. - * - * @param cookieName name of the cookie - */ - public void setCookieName(String cookieName) { - - this.cookieName = cookieName; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - - ServletResponse wrappedResponse = response; - if (response instanceof HttpServletResponse) { - wrappedResponse = new RedirectResponseWrapper((HttpServletResponse) response); - } - - chain.doFilter(request, wrappedResponse); - } - - /** - * HttpServletResponseWrapper that replaces the redirect by appropriate Javascript code. - */ - private class RedirectResponseWrapper extends HttpServletResponseWrapper { - - public RedirectResponseWrapper(HttpServletResponse response) { - - super(response); - } - - @Override - public void sendRedirect(String location) throws IOException { - - HttpServletResponse response = (HttpServletResponse) getResponse(); - String redirectPageHtml = ""; - if (location.matches(RetainAnchorFilter.this.storeUrlPattern)) { - redirectPageHtml = generateStoreAnchorRedirectPageHtml(location); - } else if (location.matches(RetainAnchorFilter.this.restoreUrlPattern)) { - redirectPageHtml = generateRestoreAnchorRedirectPageHtml(location); - } else { - super.sendRedirect(location); - return; - } - response.setContentType("text/html;charset=UTF-8"); - response.setContentLength(redirectPageHtml.length()); - response.getWriter().write(redirectPageHtml); - } - - private String generateStoreAnchorRedirectPageHtml(String location) { - - StringBuilder sb = new StringBuilder(); - - sb.append("Redirect Page\n"); - sb.append("\n\n"); - sb.append("

Redirect Page (Store Anchor)

\n"); - sb.append("Should redirect to " + location + "\n"); - sb.append("\n"); - - return sb.toString(); - } - - /** - * @author mbrunnli (Bugfix of mpickell) - * @see Forum - * post - */ - private String generateRestoreAnchorRedirectPageHtml(String location) { - - StringBuilder sb = new StringBuilder(); - - // open html - sb.append("Redirect Page"); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append("

Redirect Page (Restore Anchor)

"); - sb.append("

Should redirect to " + location + "

"); - sb.append(""); - sb.append(""); - - return sb.toString(); - } - - } -} diff --git a/oasp4j-modules/oasp4j-security/src/main/resources/io/oasp/module/security/access-control-schema.xsd b/oasp4j-modules/oasp4j-security/src/main/resources/io/oasp/module/security/access-control-schema.xsd deleted file mode 100644 index 4b256afbf..000000000 --- a/oasp4j-modules/oasp4j-security/src/main/resources/io/oasp/module/security/access-control-schema.xsd +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-modules/oasp4j-security/src/test/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaTest.java b/oasp4j-modules/oasp4j-security/src/test/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaTest.java deleted file mode 100644 index b1d8cd5c2..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/java/io/oasp/module/security/common/impl/accesscontrol/AccessControlSchemaTest.java +++ /dev/null @@ -1,247 +0,0 @@ -package io.oasp.module.security.common.impl.accesscontrol; - -import io.oasp.module.security.common.api.accesscontrol.AccessControl; -import io.oasp.module.security.common.api.accesscontrol.AccessControlGroup; -import io.oasp.module.security.common.api.accesscontrol.AccessControlPermission; -import io.oasp.module.security.common.api.accesscontrol.AccessControlProvider; -import io.oasp.module.security.common.api.accesscontrol.AccessControlSchema; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.core.io.ClassPathResource; - -/** - * This is the test-case for {@link AccessControlSchema} and {@link AccessControlSchemaXmlMapper}. - * - * @author hohwille - */ -public class AccessControlSchemaTest extends Assert { - - /** The location of the reference configuration for regression tests. */ - private static final String SCHEMA_XML = "config/app/security/access-control-schema.xml"; - - /** The location of the reference configuration with group type declaration */ - private static final String SCHEMA_XML_GROUP_TYPES = "config/app/security/access-control-schema_groupTypes.xml"; - - /** The location of the configuration with a cyclic dependency. */ - private static final String SCHEMA_XML_CYCLIC = "config/app/security/access-control-schema_cyclic.xml"; - - /** The location of the configuration that is syntactically corrupted (invalid group reference). */ - private static final String SCHEMA_XML_CORRUPTED = "config/app/security/access-control-schema_corrupted.xml"; - - /** The location of the configuration that is syntactically corrupted (invalid group reference). */ - private static final String SCHEMA_XML_ILLEGAL = "config/app/security/access-control-schema_illegal.xml"; - - /** - * The constructor. - */ - public AccessControlSchemaTest() { - - super(); - } - - /** - * Regression test for {@link AccessControlSchemaXmlMapper#write(AccessControlSchema, java.io.OutputStream)}. - * - * @throws Exception if something goes wrong. - */ - @Test - public void testWriteXml() throws Exception { - - // given - AccessControlSchema conf = createSecurityConfiguration(); - String expectedXml = readSecurityConfigurationXmlFile(); - // when - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new AccessControlSchemaXmlMapper().write(conf, baos); - String actualXml = baos.toString(); - // then - assertEquals(expectedXml.replaceAll("\\r *|\\n *", ""), actualXml); - } - - /** - * Regression test for {@link AccessControlSchemaXmlMapper#read(InputStream)}. - * - * @throws Exception if something goes wrong. - */ - @Test - public void testReadXml() throws Exception { - - // given - AccessControlSchema expectedConf = createSecurityConfiguration(); - // when - ClassPathResource resource = new ClassPathResource(SCHEMA_XML); - AccessControlSchema actualConf; - try (InputStream in = resource.getInputStream()) { - actualConf = new AccessControlSchemaXmlMapper().read(in); - } - // then - assertEquals(expectedConf, actualConf); - } - - /** - * Tests that {@link AccessControlProviderImpl} properly detects cyclic inheritance of {@link AccessControlGroup}s. - */ - @Test - public void testProviderCyclic() { - - try { - createProvider(SCHEMA_XML_CYCLIC); - fail("Exception expected!"); - } catch (IllegalStateException e) { - assertTrue(e.getMessage().startsWith("Cyclic inheritance ")); - } - } - - /** - * Tests that {@link AccessControlProviderImpl} with corrupted XML (not well-formed). - */ - @Test - public void testProviderCorrupted() { - - try { - createProvider(SCHEMA_XML_CORRUPTED); - fail("Exception expected!"); - } catch (IllegalStateException e) { - String message = e.getMessage(); - assertTrue(message, message.contains(SCHEMA_XML_CORRUPTED.toString())); - String causeMessage = e.getCause().getMessage(); - assertEquals("Unmarshalling XML failed!", causeMessage); - } - } - - /** - * Tests that {@link AccessControlProviderImpl} with illegal XML (undefined group reference). - */ - @Test - public void testProviderIllegal() { - - try { - createProvider(SCHEMA_XML_ILLEGAL); - fail("Exception expected!"); - } catch (IllegalStateException e) { - String message = e.getMessage(); - assertTrue(message, message.contains(SCHEMA_XML_ILLEGAL.toString())); - String causeMessage = e.getCause().getMessage(); - assertTrue(causeMessage, causeMessage.contains("Undefined ID \"Waiter\"")); - } - } - - /** - * Tests that {@link AccessControlProviderImpl} properly detects cyclic inheritance of {@link AccessControlGroup}s. - */ - public void testProvider() { - - AccessControlProvider provider = createProvider(SCHEMA_XML); - Set permissions = new HashSet<>(); - boolean success; - success = provider.collectAccessControls("", permissions); - assertFalse(success); - assertEquals(0, permissions.size()); - success = provider.collectAccessControls("Admin", permissions); - assertTrue(success); - assertTrue(permissions.contains(provider.getAccessControl("Customer_ReadCustomer"))); - assertTrue(permissions.contains(provider.getAccessControl("Customer_CreateCustomer"))); - assertTrue(permissions.contains(provider.getAccessControl("Customer_DeleteCustomer"))); - assertEquals(24, permissions.size()); - success = provider.collectAccessControls("ReadOnly", permissions); - assertTrue(success); - assertTrue(permissions.contains(provider.getAccessControl("Contract_ReadContractAsset"))); - assertTrue(permissions.contains(provider.getAccessControl("Contract_UpdateContractAsset"))); - assertFalse(permissions.contains(provider.getAccessControl("System_DeleteUser"))); - assertEquals(5, permissions.size()); - - } - - /** - * Tests the correct extraction of group types - */ - @Test - public void testGroupTypes() { - - ClassPathResource resource = new ClassPathResource(SCHEMA_XML_GROUP_TYPES); - AccessControlSchemaProviderImpl accessControlSchemaProvider = new AccessControlSchemaProviderImpl(); - accessControlSchemaProvider.setAccessControlSchema(resource); - AccessControlSchema accessControlSchema = accessControlSchemaProvider.loadSchema(); - List groups = accessControlSchema.getGroups(); - - Assert.assertNotNull(groups); - Assert.assertEquals(3, groups.size()); - - for (AccessControlGroup group : groups) { - if (group.getId().equals("Admin")) { - Assert.assertEquals("role", group.getType()); - } else if (group.getId().equals("ReadOnly") || group.getId().equals("ReadWrite")) { - Assert.assertEquals("group", group.getType()); - } - } - } - - private AccessControlProvider createProvider(String location) { - - ClassPathResource resource = new ClassPathResource(location); - AccessControlProviderImpl accessControlProvider = new AccessControlProviderImpl(); - AccessControlSchemaProviderImpl accessControlSchemaProvider = new AccessControlSchemaProviderImpl(); - accessControlSchemaProvider.setAccessControlSchema(resource); - accessControlProvider.setAccessControlSchemaProvider(accessControlSchemaProvider); - accessControlProvider.initialize(); - return accessControlProvider; - } - - private String readSecurityConfigurationXmlFile() throws IOException, UnsupportedEncodingException { - - ClassPathResource resource = new ClassPathResource(SCHEMA_XML); - byte[] data = Files.readAllBytes(Paths.get(resource.getURI())); - String expectedXml = new String(data, "UTF-8"); - return expectedXml; - } - - private AccessControlSchema createSecurityConfiguration() { - - AccessControlSchema conf = new AccessControlSchema(); - AccessControlGroup readOnly = new AccessControlGroup("ReadOnly"); - readOnly.getPermissions().add(new AccessControlPermission("Customer_ReadCustomer")); - readOnly.getPermissions().add(new AccessControlPermission("Customer_ReadProfile")); - readOnly.getPermissions().add(new AccessControlPermission("Customer_ReadAddress")); - readOnly.getPermissions().add(new AccessControlPermission("Contract_ReadContract")); - readOnly.getPermissions().add(new AccessControlPermission("Contract_ReadContractAsset")); - AccessControlGroup readWrite = new AccessControlGroup("ReadWrite"); - readWrite.getInherits().add(readOnly); - readWrite.getPermissions().add(new AccessControlPermission("Customer_CreateCustomer")); - readWrite.getPermissions().add(new AccessControlPermission("Customer_CreateProfile")); - readWrite.getPermissions().add(new AccessControlPermission("Customer_CreateAddress")); - readWrite.getPermissions().add(new AccessControlPermission("Contract_CreateContract")); - readWrite.getPermissions().add(new AccessControlPermission("Contract_CreateContractAsset")); - readWrite.getPermissions().add(new AccessControlPermission("Customer_UpdateCustomer")); - readWrite.getPermissions().add(new AccessControlPermission("Customer_UpdateProfile")); - readWrite.getPermissions().add(new AccessControlPermission("Customer_UpdateAddress")); - readWrite.getPermissions().add(new AccessControlPermission("Contract_UpdateContract")); - readWrite.getPermissions().add(new AccessControlPermission("Contract_UpdateContractAsset")); - AccessControlGroup admin = new AccessControlGroup("Admin"); - admin.getInherits().add(readWrite); - admin.getPermissions().add(new AccessControlPermission("Customer_DeleteCustomer")); - admin.getPermissions().add(new AccessControlPermission("Customer_DeleteProfile")); - admin.getPermissions().add(new AccessControlPermission("Customer_DeleteAddress")); - admin.getPermissions().add(new AccessControlPermission("Contract_DeleteContract")); - admin.getPermissions().add(new AccessControlPermission("Contract_DeleteContractAsset")); - admin.getPermissions().add(new AccessControlPermission("System_ReadUser")); - admin.getPermissions().add(new AccessControlPermission("System_CreateUser")); - admin.getPermissions().add(new AccessControlPermission("System_UpdateUser")); - admin.getPermissions().add(new AccessControlPermission("System_DeleteUser")); - conf.getGroups().add(readOnly); - conf.getGroups().add(readWrite); - conf.getGroups().add(admin); - return conf; - } - -} diff --git a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema.xml b/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema.xml deleted file mode 100644 index 6c2cdec6e..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - ReadOnly - - - - - - - - - - - - - - - - - ReadWrite - - - - - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_corrupted.xml b/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_corrupted.xml deleted file mode 100644 index 63b25fe56..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_corrupted.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_cyclic.xml b/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_cyclic.xml deleted file mode 100644 index 562287fb4..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_cyclic.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - Chief - - - - - Barkeeper - - - - - Waiter - Barkeeper - Cook - - - - - - - diff --git a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_groupTypes.xml b/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_groupTypes.xml deleted file mode 100644 index 7dfd6f707..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_groupTypes.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - ReadOnly - - - - - - - - ReadWrite - - - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_illegal.xml b/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_illegal.xml deleted file mode 100644 index fd4a6a9fe..000000000 --- a/oasp4j-modules/oasp4j-security/src/test/resources/config/app/security/access-control-schema_illegal.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Waiter - - - diff --git a/oasp4j-modules/oasp4j-test/pom.xml b/oasp4j-modules/oasp4j-test/pom.xml deleted file mode 100644 index c7607f7d4..000000000 --- a/oasp4j-modules/oasp4j-test/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-test - ${oasp4j.version} - ${project.artifactId} - Module with code and configuration for tests of the Open Application Standard Platform for Java (OASP4J). - - - - - org.jboss.arquillian - arquillian-bom - 1.1.7.Final - import - pom - - - - - - - junit - junit - - - org.assertj - assertj-core - - - org.springframework - spring-test - - - org.mockito - mockito-core - - - org.jboss.arquillian.junit - arquillian-junit-container - - - com.github.tomakehurst - wiremock - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryComponentTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryComponentTest.java deleted file mode 100644 index 2ca14cb59..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryComponentTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.oasp.module.test.common.api.category; - -/** - * This is the JUnit {@link org.junit.experimental.categories.Category} for a component test. - * - * @author hohwille - */ -public interface CategoryComponentTest { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryModuleTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryModuleTest.java deleted file mode 100644 index f96c5570c..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategoryModuleTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.oasp.module.test.common.api.category; - -/** - * This is the JUnit {@link org.junit.experimental.categories.Category} for a module test. - * - * @author hohwille - */ -public interface CategoryModuleTest { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySubsystemTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySubsystemTest.java deleted file mode 100644 index 32e468e1a..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySubsystemTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.oasp.module.test.common.api.category; - -/** - * This is the JUnit {@link org.junit.experimental.categories.Category} for an integration test. - * - * @author hohwille - */ -public interface CategorySubsystemTest { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySystemTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySystemTest.java deleted file mode 100644 index 1946f84d5..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/api/category/CategorySystemTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.oasp.module.test.common.api.category; - -/** - * This is the JUnit {@link org.junit.experimental.categories.Category} for an system test. - * - * @author hohwille - */ -public interface CategorySystemTest { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ComponentTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ComponentTest.java deleted file mode 100644 index 64a3efbcd..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ComponentTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.oasp.module.test.common.base; - -import io.oasp.module.test.common.api.category.CategoryComponentTest; - -import org.assertj.core.api.Assertions; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; - -/** - * This is the abstract base class for a component test. You are free to create your component tests as you like just by - * annotating {@link CategoryComponentTest} using {@link Category}. However, in most cases it will be convenient just to - * extend this class. - * - * @see CategoryComponentTest - * - * @author hohwille - */ -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class }) -@Category(CategoryComponentTest.class) -public abstract class ComponentTest extends Assertions { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ModuleTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ModuleTest.java deleted file mode 100644 index 35e76b87e..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/ModuleTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.oasp.module.test.common.base; - -import io.oasp.module.test.common.api.category.CategoryModuleTest; - -import org.assertj.core.api.Assertions; -import org.junit.experimental.categories.Category; - -/** - * This is the abstract base class for a module test. You are free to create your module tests as you like just by - * annotating {@link CategoryModuleTest} using {@link Category}. However, in most cases it will be convenient just to - * extend this class. - * - * @see CategoryModuleTest - * - * @author hohwille - */ -@Category(CategoryModuleTest.class) -public abstract class ModuleTest extends Assertions { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SubsystemTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SubsystemTest.java deleted file mode 100644 index 629604ed0..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SubsystemTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.oasp.module.test.common.base; - -import io.oasp.module.test.common.api.category.CategorySubsystemTest; - -import org.assertj.core.api.Assertions; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; - -/** - * This is the abstract base class for an integration test. You are free to create your integration tests as you like - * just by annotating {@link CategorySubsystemTest} using {@link Category}. However, in most cases it will be - * convenient just to extend this class. - * - * @see CategorySubsystemTest - * - * @author hohwille - */ -// TODO we need to either get local transport to work with CXF or we shall switch to @RunWith(Arquillian.class) -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class }) -@Category(CategorySubsystemTest.class) -public abstract class SubsystemTest extends Assertions { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SystemTest.java b/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SystemTest.java deleted file mode 100644 index 2feed6d49..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/java/io/oasp/module/test/common/base/SystemTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.oasp.module.test.common.base; - -import io.oasp.module.test.common.api.category.CategorySystemTest; - -import org.assertj.core.api.Assertions; -import org.jboss.arquillian.junit.Arquillian; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; - -/** - * This is the abstract base class for a system test. You are free to create your system tests as you like just by - * annotating {@link CategorySystemTest} using {@link Category}. However, in most cases it will be convenient just to - * extend this class. - * - * @see CategorySystemTest - * - * @author hohwille - */ -@RunWith(Arquillian.class) -@Category(CategorySystemTest.class) -public abstract class SystemTest extends Assertions { - -} diff --git a/oasp4j-modules/oasp4j-test/src/main/resources/logback.xml b/oasp4j-modules/oasp4j-test/src/main/resources/logback.xml deleted file mode 100644 index 817f6ab0f..000000000 --- a/oasp4j-modules/oasp4j-test/src/main/resources/logback.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - ${logPattern} - - - DEBUG - - - - - - - - - - - - - - diff --git a/oasp4j-modules/oasp4j-web/pom.xml b/oasp4j-modules/oasp4j-web/pom.xml deleted file mode 100644 index 680a2a531..000000000 --- a/oasp4j-modules/oasp4j-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - io.oasp.java.modules - oasp4j-web - ${oasp4j.version} - jar - ${project.artifactId} - Module for reusable web and servlet related code of the Open Application Standard Platform for Java (OASP4J). - - - - javax.servlet - javax.servlet-api - provided - - - org.springframework - spring-web - - - net.sf.m-m-m - mmm-util-core - - - - io.oasp.java.modules - oasp4j-test - test - - - - \ No newline at end of file diff --git a/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/PropertiesWebApplicationContextInitializer.java b/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/PropertiesWebApplicationContextInitializer.java deleted file mode 100644 index cdc4e496b..000000000 --- a/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/PropertiesWebApplicationContextInitializer.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.oasp.module.web.common.base; - -import java.io.IOException; -import java.util.Arrays; - -import net.sf.mmm.util.io.api.RuntimeIoException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.core.env.CompositePropertySource; -import org.springframework.core.io.support.ResourcePropertySource; -import org.springframework.web.WebApplicationInitializer; -import org.springframework.web.context.ConfigurableWebApplicationContext; - -/** - * Registers new {@link WebApplicationInitializer} which allows setting spring profiles in application properties. - * - * @author sspielma - */ -public class PropertiesWebApplicationContextInitializer implements - ApplicationContextInitializer { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(PropertiesWebApplicationContextInitializer.class); - - /** - * List of application property resource names. - */ - private String[] applicationPropertyResources = { "classpath:/config/app/application-default.properties", - "classpath:/config/env/application.properties" }; - - @Override - public void initialize(ConfigurableWebApplicationContext applicationContext) { - - CompositePropertySource compositePropertySource = new CompositePropertySource("application properties"); - for (String propertyName : Arrays.asList(this.applicationPropertyResources)) { - try { - LOG.debug("Registering " + propertyName + " as property source."); - compositePropertySource.addPropertySource(new ResourcePropertySource(propertyName)); - applicationContext.getEnvironment().getPropertySources().addFirst(compositePropertySource); - } catch (IOException e) { - throw new RuntimeIoException(e); - } - } - } - - /** - * Overwrites default application property resources. - * - * @param applicationPropertyResources the applicationPropertyResources to set - */ - public void setApplicationPropertyResources(String... applicationPropertyResources) { - - this.applicationPropertyResources = applicationPropertyResources; - } -} diff --git a/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/ToggleFilterWrapper.java b/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/ToggleFilterWrapper.java deleted file mode 100644 index ebb8cbc5f..000000000 --- a/oasp4j-modules/oasp4j-web/src/main/java/io/oasp/module/web/common/base/ToggleFilterWrapper.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.oasp.module.web.common.base; - -import java.io.IOException; - -import javax.annotation.PostConstruct; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is responsible for wrapping a {@link Filter} and allows to be {@link #setDisabled(Boolean) disabled} e.g. - * for development tests (e.g. via some {@link System#getProperty(String) system property}. In case the filter gets - * {@link #setDisabled(Boolean) disabled} a WARNING log message is produced and also written to {@link System#err}.
- * - * Here is an example spring XML config from our sample application that allows to disable the CsrfFilter - * via a {@link System#getProperties() system property} (-DCsrfDisabled=true): - * - *
- * <bean id="CsrfFilterWrapper" class="io.oasp.gastronomy.restaurant.general.service.impl.rest.ToggleFilterWrapper">
- *   <property name="delegateFilter" ref="CsrfFilter"/>
- *   <property name="disabledString" value="#{systemProperties['CsrfDisabled']}"/>
- * </bean>
- * 
- * - * @author hohwille - */ -public class ToggleFilterWrapper implements Filter { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(ToggleFilterWrapper.class); - - /** - * The delegated Filter. - */ - private Filter delegateFilter; - - /** - * Is set if this filter is disabled. - */ - private Boolean disabled; - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - - } - - @PostConstruct - public void initialize() { - - if (this.disabled) { - String message = - "****** FILTER " + this.delegateFilter - + " HAS BEEN DISABLED! THIS FEATURE SHOULD ONLY BE USED IN DEVELOPMENT MODE ******"; - LOG.warn(message); - // CHECKSTYLE:OFF (for development only) - System.err.println(message); - // CHECKSTYLE:ON - } - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - - if (!this.disabled) { - this.delegateFilter.doFilter(request, response, chain); - } else { - chain.doFilter(request, response); - } - } - - @Override - public void destroy() { - - } - - /** - * @param delegateFilter the filter to delegate to - */ - public void setDelegateFilter(Filter delegateFilter) { - - this.delegateFilter = delegateFilter; - } - - /** - * @param disabled indicates if this filter is disabled - */ - public void setDisabled(Boolean disabled) { - - this.disabled = disabled; - } - - /** - * @param disabledString the String to be parsed to a boolean - */ - public void setDisabledString(String disabledString) { - - setDisabled(Boolean.parseBoolean(disabledString)); - } - - /** - * @return disabled - */ - public Boolean isDisabled() { - - return this.disabled; - } -} diff --git a/oasp4j-modules/pom.xml b/oasp4j-modules/pom.xml deleted file mode 100644 index 65c250aec..000000000 --- a/oasp4j-modules/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j - dev-SNAPSHOT - - oasp4j-modules - dev-SNAPSHOT - pom - ${project.artifactId} - Reusable modules of the Open Application Standard Platform for Java (OASP4J). - - - oasp4j-logging - oasp4j-test - oasp4j-configuration - oasp4j-beanmapping - oasp4j-rest - oasp4j-security - oasp4j-jpa - oasp4j-jpa-envers - oasp4j-web - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - io.oasp.java - oasp4j-bom - ${oasp4j.version} - pom - import - - - - - - - org.slf4j - slf4j-api - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - private - ${project.reporting.outputEncoding} - ${project.build.sourceEncoding} - true - ${user.dir}/src/main/javadoc/stylesheet.css - - - http://docs.oracle.com/javase/7/docs/api/ - http://oasp.github.io/oasp4j/maven/apidocs/ - - JavaDocs for ${project.name} - JavaDocs for ${project.name} - - - - oasp.javadoc - - javadoc - - - - oasp.javadoc.aggregate - - aggregate - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractCto.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractCto.java deleted file mode 100644 index 538a9a9dd..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractCto.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common.api.to; - -import net.sf.mmm.util.transferobject.api.CompositeTo; - -/** - * Abstract base class for a {@link CompositeTo composite transfer-object} in this application. - * - * @author hohwille - */ -public abstract class AbstractCto extends CompositeTo { - - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AbstractCto() { - - super(); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractEto.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractEto.java deleted file mode 100644 index 295c09214..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractEto.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common.api.to; - -import net.sf.mmm.util.transferobject.api.EntityTo; - -/** - * Abstract base class for an {@link EntityTo entity transfer-object} in this application. - * - * @author hohwille - * @author erandres - */ -public abstract class AbstractEto extends EntityTo { - - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AbstractEto() { - - super(); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractTo.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractTo.java deleted file mode 100644 index dbf66ff4f..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/AbstractTo.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common.api.to; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * Abstract class for a plain {@link net.sf.mmm.util.transferobject.api.TransferObject} that is neither a - * {@link AbstractEto ETO} nor a {@link AbstractCto CTO}. - * - * @author hohwille - */ -public class AbstractTo extends AbstractTransferObject { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AbstractTo() { - - super(); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java deleted file mode 100644 index 5a23e6ab8..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api; - -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; - -/** - * Interface for Offermanagement. - * - * @author loverbec - */ -public interface Offermanagement extends UcFindOffer, UcManageOffer, UcManageProduct, UcFindProduct { - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java deleted file mode 100644 index 909191482..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.MenuItem; - -import java.util.Objects; - -/** - * The {@link AbstractEto ETO} for a {@link MenuItem}. - * - * @author jozitz - */ -public abstract class MenuItemEto extends AbstractEto implements MenuItem { - - private static final long serialVersionUID = 1L; - - private String name; - - private String description; - - /** - * The constructor. - */ - public MenuItemEto() { - - super(); - } - - @Override - public String getName() { - - return this.name; - } - - @Override - public void setName(String name) { - - this.name = name; - } - - @Override - public String getDescription() { - - return this.description; - } - - @Override - public void setDescription(String description) { - - this.description = description; - } - - @Override - public int hashCode() { - - final Integer prime = 31; - Integer result = super.hashCode(); - result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); - result = prime * result + ((this.description == null) ? 0 : this.description.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - MenuItemEto other = (MenuItemEto) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!Objects.equals(this.description, other.description)) { - return false; - } - return true; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java deleted file mode 100644 index a065576e4..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindOffer.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; - -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.module.jpa.common.api.to.PaginatedListTo; - -import java.util.List; - -/** - * Interface of UcFindOffer to centralize documentation and signatures of methods. - * - * @author mbrunnli - * @since dev - */ -public interface UcFindOffer { - - /** - * Gets an {@link OfferEto} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. - */ - OfferEto findOffer(Long id); - - /** - * Gets an {@link OfferCto} using its entity identifier. - * - * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. - * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no - * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. - */ - OfferCto findOfferCto(Long id); - - /** - * @return the {@link List} with all available {@link OfferEto}s. - */ - List findAllOffers(); - - /** - * Returns a list of offers matching the search criteria. - * - * @param criteria the {@link OfferSearchCriteriaTo}. - * @return the {@link List} of matching {@link OfferEto}s. - */ - PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria); - - /** - * @param offerFilterBo is the {@link OfferFilter offers filter criteria} - * @param sortBy is the {@link OfferSortBy} attribute, which defines the sorting. - * @return the {@link List} with all {@link OfferEto}s that match the {@link OfferFilter} criteria. - */ - List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy); - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java deleted file mode 100644 index d3b55df3c..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageOffer.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; - -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; - -import javax.validation.Valid; - -/** - * Interface of UcManageOffer to centralize documentation and signatures of methods. - */ -public interface UcManageOffer { - - /** - * Deletes an {@link OfferEto} by its {@link OfferEto#getId() id}. - * - * @param offerId is the {@link OfferEto#getId() id} that identifies the {@link OfferEto} to be deleted. - */ - void deleteOffer(Long offerId); - - /** - * If no ID is contained creates the {@link OfferEto} for the first time. Else it updates the {@link OfferEto} with - * given ID. If no {@link OfferEto} with given ID is present, an exception will be thrown. - * - * @param offer the {@link OfferEto} to persist. - * @return the generated/updated offer - */ - OfferEto saveOffer(@Valid OfferEto offer); - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java deleted file mode 100644 index aaa11e286..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcManageProduct.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; - -import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; - -import java.sql.Blob; - -/** - * Interface of UcManageProduct to centralize documentation and signatures of methods. - * - * @author mbrunnli - * @since dev - */ -public interface UcManageProduct { - - /** - * Checks, whether a given {@link ProductEto} is in use by at least one {@link OfferEto}. - * - * @param product product to check if it is in use - * @return {@code true}, if there are no {@link OfferEto offers}, that use the given {@link ProductEto}. {@code false} - * otherwise. - */ - boolean isProductInUseByOffer(ProductEto product); - - /** - * If no ID is contained creates the {@link ProductEto} for the first time. Else it updates the {@link ProductEto} - * with given ID. If no {@link ProductEto} with given ID is present, an exception will be thrown. - * - * @param product the {@link ProductEto} to persist. - * @return the persisted {@link ProductEto}. - */ - ProductEto saveProduct(ProductEto product); - - /** - * Deletes a {@link ProductEto}. - * - * @param productId is the ID of the {@link ProductEto} to delete - */ - void deleteProduct(Long productId); - - /** - * Updates the picture of the product. - * - * @param productId is the ID of the {@link ProductEto} to update the picture - * @param blob is the binary representation of the picture - * @param binaryObjectEto is the mimeType of the blob - */ - void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto); - - /** - * Deletes the Picture of the {@link ProductEto}. - * - * @param productId is the ID of the {@link ProductEto} to delte the picture - */ - void deleteProductPicture(Long productId); - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java deleted file mode 100644 index 5b7fc9019..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractOfferUc.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase; - -import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.OfferDao; - -import javax.inject.Inject; - -/** - * Abstract use case for Offers, which provides access to the commonly necessary data access objects. - */ -public class AbstractOfferUc extends AbstractUc { - - /** @see #getOfferDao() */ - private OfferDao offerDao; - - /** - * Returns the field 'offerDao'. - * - * @return the {@link OfferDao} instance. - */ - public OfferDao getOfferDao() { - - return this.offerDao; - } - - /** - * Sets the field 'offerDao'. - * - * @param offerDao New value for offerDao - */ - @Inject - public void setOfferDao(OfferDao offerDao) { - - this.offerDao = offerDao; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java deleted file mode 100644 index b06dd2b5f..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/base/usecase/AbstractProductUc.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase; - -import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.MealDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.ProductDao; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.SideDishDao; - -import javax.inject.Inject; - -/** - * Abstract use case for Products, which provides access to the commonly necessary data access objects. - * - * @author mbrunnli - * @since dev - */ -public abstract class AbstractProductUc extends AbstractUc { - - /** - * @see #setProductDao(ProductDao) - */ - private ProductDao productDao; - - /** - * @see #setMealDao(MealDao) - */ - private MealDao mealDao; - - /** - * @see #setDrinkDao(DrinkDao) - */ - private DrinkDao drinkDao; - - /** - * @see #setSideDishDao(SideDishDao) - */ - private SideDishDao sideDishDao; - - /** - * @return productDao - */ - public ProductDao getProductDao() { - - return this.productDao; - } - - /** - * @return mealDao - */ - public MealDao getMealDao() { - - return this.mealDao; - } - - /** - * @return drinkDao - */ - public DrinkDao getDrinkDao() { - - return this.drinkDao; - } - - /** - * @return sideDishDao - */ - public SideDishDao getSideDishDao() { - - return this.sideDishDao; - } - - /** - * Sets the field 'productDao'. - * - * @param productDao New value for productDao - */ - @Inject - public void setProductDao(ProductDao productDao) { - - this.productDao = productDao; - } - - /** - * @param mealDao the {@link MealDao} to {@link Inject}. - */ - @Inject - public void setMealDao(MealDao mealDao) { - - this.mealDao = mealDao; - } - - /** - * @param drinkDao the {@link DrinkDao} to {@link Inject}. - */ - @Inject - public void setDrinkDao(DrinkDao drinkDao) { - - this.drinkDao = drinkDao; - } - - /** - * @param sideDishDao the {@link SideDishDao} to {@link Inject}. - */ - @Inject - public void setSideDishDao(SideDishDao sideDishDao) { - - this.sideDishDao = sideDishDao; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java deleted file mode 100644 index 1bbb69b91..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java +++ /dev/null @@ -1,254 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.impl; - -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; -import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; -import io.oasp.gastronomy.restaurant.general.logic.base.AbstractComponentFacade; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; -import io.oasp.module.jpa.common.api.to.PaginatedListTo; - -import java.sql.Blob; -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Named; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation class for {@link Offermanagement}. - * - * @author loverbec - */ -@Named -public class OffermanagementImpl extends AbstractComponentFacade implements Offermanagement { - - private static final Logger LOG = LoggerFactory.getLogger(OffermanagementImpl.class); - - private UcFindOffer ucFindOffer; - - private UcManageOffer ucManageOffer; - - private UcFindProduct ucFindProduct; - - private UcManageProduct ucManageProduct; - - /** - * The constructor. - */ - public OffermanagementImpl() { - - super(); - } - - @Override - public OfferEto findOffer(Long id) { - - return this.ucFindOffer.findOffer(id); - } - - @Override - public OfferCto findOfferCto(Long id) { - - return this.ucFindOffer.findOfferCto(id); - } - - @Override - public List findAllOffers() { - - return this.ucFindOffer.findAllOffers(); - } - - @Override - public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { - - return this.ucFindOffer.findOfferEtos(criteria); - } - - @Override - public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { - - return this.ucFindOffer.findOffersFiltered(offerFilterBo, sortBy); - } - - @Override - public void deleteOffer(Long offerId) { - - this.ucManageOffer.deleteOffer(offerId); - } - - @Override - public OfferEto saveOffer(OfferEto offer) { - - return this.ucManageOffer.saveOffer(offer); - } - - @Override - public boolean isProductInUseByOffer(ProductEto product) { - - return this.ucManageProduct.isProductInUseByOffer(product); - } - - @Override - public ProductEto saveProduct(ProductEto product) { - - return this.ucManageProduct.saveProduct(product); - } - - @Override - public void deleteProduct(Long productId) { - - this.ucManageProduct.deleteProduct(productId); - } - - @Override - public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { - - this.ucManageProduct.updateProductPicture(productId, blob, binaryObjectEto); - } - - @Override - public void deleteProductPicture(Long productId) { - - this.ucManageProduct.deleteProductPicture(productId); - } - - @Override - public ProductEto findProduct(Long id) { - - return this.ucFindProduct.findProduct(id); - } - - @Override - public ProductEto findProductByRevision(Long id, Number revision) { - - return this.ucFindProduct.findProductByRevision(id, revision); - } - - @Override - public MealEto findMeal(Long id) { - - return this.ucFindProduct.findMeal(id); - } - - @Override - public DrinkEto findDrink(Long id) { - - return this.ucFindProduct.findDrink(id); - } - - @Override - public SideDishEto findSideDish(Long id) { - - return this.ucFindProduct.findSideDish(id); - } - - @Override - public List findAllProducts() { - - return this.ucFindProduct.findAllProducts(); - } - - @Override - public List findAllMeals() { - - return this.ucFindProduct.findAllMeals(); - } - - @Override - public List findAllDrinks() { - - return this.ucFindProduct.findAllDrinks(); - } - - @Override - public List findAllSideDishes() { - - return this.ucFindProduct.findAllSideDishes(); - } - - @Override - public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { - - return this.ucFindProduct.findProductsFiltered(productFilterBo, sortBy); - } - - @Override - public BinaryObjectEto findProductPicture(Long productId) { - - return this.ucFindProduct.findProductPicture(productId); - } - - @Override - public PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria) { - - return this.ucFindProduct.findProductEtos(criteria); - } - - @Override - public Blob findProductPictureBlob(Long productId) { - - return this.ucFindProduct.findProductPictureBlob(productId); - } - - /** - * Sets the field 'ucFindOffer'. - * - * @param ucFindOffer New value for ucFindOffer - */ - @Inject - @UseCase - public void setUcFindOffer(UcFindOffer ucFindOffer) { - - this.ucFindOffer = ucFindOffer; - } - - /** - * Sets the field 'ucManageOffer'. - * - * @param ucManageOffer New value for ucManageOffer - */ - @Inject - @UseCase - public void setUcManageOffer(UcManageOffer ucManageOffer) { - - this.ucManageOffer = ucManageOffer; - } - - /** - * @param ucFindProduct new value of {@link #getucFindProduct}. - */ - @Inject - @UseCase - public void setUcFindProduct(UcFindProduct ucFindProduct) { - - this.ucFindProduct = ucFindProduct; - } - - /** - * @param ucManageProduct new value of {@link #getucManageProduct}. - */ - @Inject - @UseCase - public void setUcManageProduct(UcManageProduct ucManageProduct) { - - this.ucManageProduct = ucManageProduct; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java deleted file mode 100644 index 9d3cf72f1..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindOfferImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; - -import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; -import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractOfferUc; -import io.oasp.module.jpa.common.api.to.PaginatedListTo; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.security.RolesAllowed; -import javax.inject.Inject; -import javax.inject.Named; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.annotation.Validated; - -/** - * Use case implementation for searching, filtering and getting Offers - */ -@Named -@UseCase -@Validated -public class UcFindOfferImpl extends AbstractOfferUc implements UcFindOffer { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(UcFindOfferImpl.class); - - /** Use case for finding products */ - private UcFindProduct ucFindProduct; - - @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public OfferEto findOffer(Long id) { - - LOG.debug("Get OfferEto with id '{}' from database.", id); - return getBeanMapper().map(getOfferDao().findOne(id), OfferEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { - - criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); - PaginatedListTo offers = getOfferDao().findOffers(criteria); - return mapPaginatedEntityList(offers, OfferEto.class); - } - - @Override - @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) - public OfferCto findOfferCto(Long id) { - - LOG.debug("Get OfferCTO with id '{}' from database.", id); - OfferCto result = new OfferCto(); - // offer - OfferEto offerEto = findOffer(id); - if (offerEto == null) { - return null; - } - result.setOffer(offerEto); - // meal - Long mealId = offerEto.getMealId(); - if (mealId != null) { - result.setMeal(this.ucFindProduct.findMeal(mealId)); - } - // drink - Long drinkId = offerEto.getDrinkId(); - if (drinkId != null) { - result.setDrink(this.ucFindProduct.findDrink(drinkId)); - } - // sideDish - Long sideDishId = offerEto.getSideDishId(); - if (sideDishId != null) { - result.setSideDish(this.ucFindProduct.findSideDish(sideDishId)); - } - return result; - } - - @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public List findAllOffers() { - - LOG.debug("Get all offers from database."); - return getBeanMapper().mapList(getOfferDao().findAll(), OfferEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_OFFER) - public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { - - List offers = getOfferDao().findOffersFiltered(offerFilterBo, sortBy); - LOG.debug("'" + offers.size() + "' offers fetched."); - - List offerBos = new ArrayList<>(offers.size()); - for (OfferEntity o : offers) { - offerBos.add(getBeanMapper().map(o, OfferEto.class)); - } - return offerBos; - } - - /** - * @param ucFindProduct new value of {@link #getucFindProduct}. - */ - @Inject - @UseCase - public void setUcFindProduct(UcFindProduct ucFindProduct) { - - this.ucFindProduct = ucFindProduct; - } -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java deleted file mode 100644 index 38a1cd21f..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcFindProductImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; - -import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; -import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; -import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; -import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractProductUc; -import io.oasp.module.jpa.common.api.to.PaginatedListTo; - -import java.sql.Blob; -import java.util.List; - -import javax.annotation.security.RolesAllowed; -import javax.inject.Inject; -import javax.inject.Named; - -import net.sf.mmm.util.exception.api.ObjectMismatchException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.annotation.Validated; - -/** - * Use case implementation for searching, filtering and getting Products. - * - * @author mbrunnli - * @since dev - */ -@Named -@UseCase -@Validated -public class UcFindProductImpl extends AbstractProductUc implements UcFindProduct { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(UcFindProductImpl.class); - - /** Use case for managing binary objects */ - private UcManageBinaryObject ucManageBinaryObject; - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public ProductEto findProduct(Long id) { - - LOG.debug("Get Product with id '" + id + "' from database."); - ProductEntity product = getProductDao().findOne(id); - if (product == null) { - return null; - } else { - return getBeanMapper().map(product, ProductEto.class); - } - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public MealEto findMeal(Long id) { - - ProductEto product = findProduct(id); - try { - return (MealEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, MealEto.class, e); - } - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public DrinkEto findDrink(Long id) { - - ProductEto product = findProduct(id); - try { - return (DrinkEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, DrinkEto.class, e); - } - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public SideDishEto findSideDish(Long id) { - - ProductEto product = findProduct(id); - try { - return (SideDishEto) product; - } catch (ClassCastException e) { - throw new ObjectMismatchException(product, SideDishEto.class, e); - } - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllProducts() { - - LOG.debug("Get all products from database."); - return getBeanMapper().mapList(getProductDao().findAll(), ProductEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllMeals() { - - LOG.debug("Get all meals with from database."); - return getBeanMapper().mapList(getMealDao().findAll(), MealEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllDrinks() { - - LOG.debug("Get all drinks with from database."); - return getBeanMapper().mapList(getDrinkDao().findAll(), DrinkEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findAllSideDishes() { - - LOG.debug("Get all sidedishes with from database."); - return getBeanMapper().mapList(getSideDishDao().findAll(), SideDishEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria) { - - criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); - PaginatedListTo products = getProductDao().findProducts(criteria); - return mapPaginatedEntityList(products, ProductEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { - - LOG.debug("Fetch filtered offers."); - return getBeanMapper().mapList(getProductDao().findProductsFiltered(productFilterBo, sortBy), ProductEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT) - public BinaryObjectEto findProductPicture(Long productId) { - - return this.ucManageBinaryObject.findBinaryObject(findProduct(productId).getPictureId()); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) - public Blob findProductPictureBlob(Long productId) { - - return this.ucManageBinaryObject.getBinaryObjectBlob(findProductPicture(productId).getId()); - } - - @Override - @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) - public ProductEto findProductByRevision(Long id, Number revision) { - - LOG.debug("Get Product with id '" + id + "' and revision '" + revision + "' from database."); - ProductEntity product = getProductDao().load(id, revision); - if (product == null) { - return null; - } else { - return getBeanMapper().map(product, ProductEto.class); - } - } - - /** - * @param ucManageBinaryObject new value of {@link #getucManageBinaryObject}. - */ - @Inject - @UseCase - public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { - - this.ucManageBinaryObject = ucManageBinaryObject; - } -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java deleted file mode 100644 index 97c2de54c..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageOfferImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; - -import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.exception.OfferEmptyException; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractOfferUc; - -import java.util.Objects; - -import javax.annotation.security.RolesAllowed; -import javax.inject.Named; -import javax.validation.Valid; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.annotation.Validated; - -/** - * Use case implementation for modifying and deleting Offers - */ -@Named -@UseCase -@Validated -public class UcManageOfferImpl extends AbstractOfferUc implements UcManageOffer { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(UcManageOfferImpl.class); - - @Override - @RolesAllowed(PermissionConstants.DELETE_OFFER) - public void deleteOffer(Long offerId) { - - getOfferDao().delete(offerId); - } - - @Override - @RolesAllowed(PermissionConstants.SAVE_OFFER) - public OfferEto saveOffer(@Valid OfferEto offer) { - - Objects.requireNonNull(offer, "offer"); - - if ((offer.getMealId() == null) && (offer.getDrinkId() == null) && (offer.getSideDishId() == null)) { - throw new OfferEmptyException(offer); - } else { - OfferEntity persistedOffer = getOfferDao().save(getBeanMapper().map(offer, OfferEntity.class)); - return getBeanMapper().map(persistedOffer, OfferEto.class); - } - } -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java b/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java deleted file mode 100644 index c2d7b116b..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/usecase/UcManageProductImpl.java +++ /dev/null @@ -1,174 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.impl.usecase; - -import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; -import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; -import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductType; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcManageProduct; -import io.oasp.gastronomy.restaurant.offermanagement.logic.base.usecase.AbstractProductUc; - -import java.sql.Blob; -import java.util.List; -import java.util.Objects; - -import javax.annotation.security.RolesAllowed; -import javax.inject.Inject; -import javax.inject.Named; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.validation.annotation.Validated; - -/** - * Use case implementation for modifying and deleting Offers - * - * @author mbrunnli - * @since dev - */ -@Named -@UseCase -@Validated -public class UcManageProductImpl extends AbstractProductUc implements UcManageProduct { - - /** Logger instance. */ - private static final Logger LOG = LoggerFactory.getLogger(UcManageProductImpl.class); - - /** Use case to find Offers */ - private UcFindOffer ucFindOffer; - - /** Use case for managing binary objects */ - private UcManageBinaryObject ucManageBinaryObject; - - @Override - @RolesAllowed(PermissionConstants.SAVE_PRODUCT) - public ProductEto saveProduct(ProductEto product) { - - Objects.requireNonNull(product, "product"); - - ProductEntity persistedProduct = getProductDao().save(getBeanMapper().map(product, ProductEntity.class)); - return getBeanMapper().map(persistedProduct, ProductEto.class); - } - - @Override - @RolesAllowed(PermissionConstants.DELETE_PRODUCT) - public void deleteProduct(Long productId) { - - getProductDao().delete(productId); - } - - @Override - @RolesAllowed(PermissionConstants.SAVE_PRODUCT_PICTURE) - public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { - - ProductEntity product = getProductDao().findOne(productId); - binaryObjectEto = this.ucManageBinaryObject.saveBinaryObject(blob, binaryObjectEto); - product.setPictureId(binaryObjectEto.getId()); - getProductDao().save(product); - - } - - @Override - @RolesAllowed(PermissionConstants.DELETE_PRODUCT_PICTURE) - public void deleteProductPicture(Long productId) { - - ProductEntity product = getProductDao().findOne(productId); - this.ucManageBinaryObject.deleteBinaryObject(product.getPictureId()); - - } - - @Override - @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) - public boolean isProductInUseByOffer(ProductEto product) { - - LOG.debug("Get all offers from database for the given product with id '" + product.getId() + "'."); - - List persistedOffers = this.ucFindOffer.findAllOffers(); - - /* - * Check the occurrence of a product within all offers. Therefore, only check for a instance of a product type - * product type. - */ - ProductType productType = null; - - if (product instanceof DrinkEto) { - LOG.debug("The given product is an instance of Drink '" + product.getDescription() + "', id '" + product.getId() - + "'. Check all Offer-Drinks for that given occurrence."); - productType = ProductType.DRINK; - } else if (product instanceof MealEto) { - LOG.debug("The given product is an instance of Meal '" + product.getDescription() + "', id '" + product.getId() - + "'. Check all Offer-Meals for that given occurrence."); - productType = ProductType.MEAL; - } else if (product instanceof SideDishEto) { - LOG.debug("The given product is an instance of SideDish '" + product.getDescription() + "', id '" - + product.getId() + "'. Check all Offer-SideDishes for that given occurrence."); - productType = ProductType.SIDEDISH; - } - - if (productType == null) { - LOG.debug("The given product not in use by an offer."); - return false; - } - - for (OfferEto offer : persistedOffers) { - - if (productType.isDrink()) { - if (Objects.equals(offer.getDrinkId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - - } - - if (productType.isMeal()) { - if (Objects.equals(offer.getMealId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - } - - if (productType.isSideDish()) { - if (Objects.equals(offer.getSideDishId(), product.getId())) { - LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" - + offer.getDescription() + "'."); - return true; - } - continue; - } - } - - LOG.debug("The given product not in use by an offer."); - return false; - } - - /** - * @param ucManageBinaryObject new value of {@link #getucManageBinaryObject}. - */ - @Inject - @UseCase - public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { - - this.ucManageBinaryObject = ucManageBinaryObject; - } - - /** - * @param ucFindOffer new value of {@link #getucFindOffer}. - */ - @Inject - @UseCase - public void setUcFindOffer(UcFindOffer ucFindOffer) { - - this.ucFindOffer = ucFindOffer; - } -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/application-default.properties b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/application-default.properties deleted file mode 100644 index 1eb541b28..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/application-default.properties +++ /dev/null @@ -1,40 +0,0 @@ -# --------------------------------------------------------------------------- -# This configuration file contains the properties with their default values, -# that are potentially environment specific. As a best practice you should -# provide production proof settings here that can be used as fallback. -# -# These properties can be overridden per environment in the file -# /config/env/application.properties on your classpath. If you are using -# Tomcat place this file in the following location: -# ${CATALINA_BASE}/lib/config/env/application.properties -# --------------------------------------------------------------------------- - -# --------------------------------------------------------------------------- -# Persistence and database -# --------------------------------------------------------------------------- -#database.user.login = ... -#database.user.password = ... -#database.url = ... -database.hibernate.dialect = org.hibernate.dialect.H2Dialect -database.datasource = org.h2.jdbcx.JdbcDataSource -database.hibernate.hbm2ddl.auto = validate -database.hibernate.show.sql = false -database.migration.auto = true -database.migration.testdata = false -database.migration.clean = false -# Port for internal H2 Database -database.h2.server.port = ${oasp.db.port} - -# Activate spring profiles -#spring.profiles.active = integrationTest - -# --------------------------------------------------------------------------- -# Security -# --------------------------------------------------------------------------- -# ATTENTION: These are the settings for production. Only change in development and test environments! -security.expose.error.details = false - -# Logging -log.console.disabled = true -#log.dir = ${catalina.base}/logs/ -log.dir = ../logs/ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/beans-application.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/beans-application.xml deleted file mode 100644 index 131e91569..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/beans-application.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-common.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-common.xml deleted file mode 100644 index 5c1a49ded..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-common.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - classpath:/config/app/application-default.properties - classpath:/config/env/application.properties - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-dozer.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-dozer.xml deleted file mode 100644 index ba343cc5a..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/beans-dozer.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - config/app/common/dozer-mapping.xml - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/NamedQueries.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/NamedQueries.xml deleted file mode 100644 index 96048e280..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/NamedQueries.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-dataaccess.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-dataaccess.xml deleted file mode 100644 index dc83dd525..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-dataaccess.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-plain.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-plain.xml deleted file mode 100644 index a93ff54c8..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-plain.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-server.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-server.xml deleted file mode 100644 index 4d2d3aaea..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-db-server.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - -tcp - -tcpAllowOthers - -tcpPort - ${database.h2.server.port} - - - - - \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-jpa.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-jpa.xml deleted file mode 100644 index f5c5b865d..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/dataaccess/beans-jpa.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - io.oasp.gastronomy.restaurant.*.dataaccess - io.oasp.module.jpa.dataaccess.api - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/logic/beans-logic.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/logic/beans-logic.xml deleted file mode 100644 index ca88e5e47..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/logic/beans-logic.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security-filters.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security-filters.xml deleted file mode 100644 index 93a5b05fe..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security-filters.xml +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security.xml deleted file mode 100644 index 52cc22c94..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/beans-security.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-monitoring.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-monitoring.xml deleted file mode 100644 index 6ffadcf29..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-monitoring.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-service.xml b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-service.xml deleted file mode 100644 index e2a03998c..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/service/beans-service.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/env/application.properties b/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/env/application.properties deleted file mode 100644 index a64836c69..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/env/application.properties +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------------------------------- -# This file contains the environment specific properties of the application. -# It should contain only parameters managed by system operations. -# This current file contains the settings for the development environment. -# -# It shall never be included in the deliverable of the application (WAR file). -# Therefore it is excluded during the build process with Maven. -# On the actual environment this file shall be provided with the according -# and correct settings in the following location of tomcat: -# ${CATALINA_BASE}/lib/config/env/application.properties -# ---------------------------------------------------------------------------- - -# Database -database.user.login = sa -database.user.password = -database.url = jdbc:h2:tcp://localhost:${oasp.db.port}/./.sample;INIT=create schema if not exists public -database.migration.auto = true -database.migration.clean = true - -database.hibernate.hbm2ddl.auto = update - -# Logging -log.console.disabled = false -log.dir = ${WORKSPACE_PATH}/logs/ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0001__Create_schema.sql b/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0001__Create_schema.sql deleted file mode 100644 index 12878a00a..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0001__Create_schema.sql +++ /dev/null @@ -1,100 +0,0 @@ -CREATE USER IF NOT EXISTS SA SALT '0f7d070a6a5f2b60' HASH 'cd3e105f0486a1a04aa8fffd2dc2afda0bec8c1832b5b95fab0a67d088ad1e0c' ADMIN; -CREATE SEQUENCE PUBLIC.HIBERNATE_SEQUENCE START WITH 1000000; -CREATE CACHED TABLE PUBLIC.BILL( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - payed BOOLEAN NOT NULL, - tip DECIMAL(19, 2), - total DECIMAL(19, 2) -); -CREATE CACHED TABLE PUBLIC.BILL_ORDERPOSITION( - bill_id BIGINT NOT NULL, - orderpositions_id BIGINT NOT NULL -); -CREATE CACHED TABLE PUBLIC.OFFER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - description VARCHAR(255), - name VARCHAR(255), - price DECIMAL(19, 2), - number BIGINT, - state INTEGER, - drink_id BIGINT, - meal_id BIGINT, - sideDish_id BIGINT -); -CREATE CACHED TABLE PUBLIC.ORDERPOSITION( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - comment VARCHAR(255), - cook_id BIGINT, - offer_id BIGINT, - offerName VARCHAR(255), - price DECIMAL(19, 2), - state INTEGER, - order_id BIGINT -); -CREATE CACHED TABLE PUBLIC.PRODUCT( - dtype VARCHAR(31) NOT NULL, - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - description VARCHAR(255), - name VARCHAR(255), - alcoholic BOOLEAN -); -CREATE CACHED TABLE PUBLIC.RESTAURANTTABLE( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - number BIGINT NOT NULL CHECK (NUMBER >= 0), - state INTEGER, - waiter_id BIGINT -); -CREATE CACHED TABLE PUBLIC.STAFFMEMBER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - firstname VARCHAR(255), - lastname VARCHAR(255), - login VARCHAR(255), - role INTEGER -); -CREATE CACHED TABLE PUBLIC.RESTAURANTORDER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - state INTEGER, - table_id BIGINT NOT NULL -); -CREATE CACHED TABLE PUBLIC.PRODUCT_AUD( - revtype TINYINT, - description VARCHAR(255), - name VARCHAR(255), - pictureId BIGINT, - alcoholic BOOLEAN, - dtype VARCHAR(31) NOT NULL, - id BIGINT NOT NULL, - rev BIGINT NOT NULL -); -CREATE CACHED TABLE PUBLIC.REVINFO( - id BIGINT NOT NULL generated by default as identity (start with 1), - timestamp BIGINT NOT NULL, - user VARCHAR(255) -); -ALTER TABLE PUBLIC.BILL ADD CONSTRAINT PUBLIC.PK_BILL PRIMARY KEY(id); -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.PK_OFFER PRIMARY KEY(id); -ALTER TABLE PUBLIC.ORDERPOSITION ADD CONSTRAINT PUBLIC.PK_ORDERPOSITON PRIMARY KEY(id); -ALTER TABLE PUBLIC.PRODUCT ADD CONSTRAINT PUBLIC.PK_PRODUCT PRIMARY KEY(id); -ALTER TABLE PUBLIC.RESTAURANTTABLE ADD CONSTRAINT PUBLIC.PK_RESTAURANTTABLE PRIMARY KEY(id); -ALTER TABLE PUBLIC.STAFFMEMBER ADD CONSTRAINT PUBLIC.PK_STAFFMEMEBER PRIMARY KEY(id); -ALTER TABLE PUBLIC.RESTAURANTORDER ADD CONSTRAINT PUBLIC.PK_RESTAURANTORDER PRIMARY KEY(id); - -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.UC_OFFER_NAME UNIQUE(name); -ALTER TABLE PUBLIC.RESTAURANTTABLE ADD CONSTRAINT PUBLIC.UC_TABLE_NUMBER UNIQUE(number); -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.UC_OFFER_NUMBER UNIQUE(number); -ALTER TABLE PUBLIC.STAFFMEMBER ADD CONSTRAINT PUBLIC.UC_STAFFMEMBER_LOGIN UNIQUE(login); - -ALTER TABLE PUBLIC.ORDERPOSITION ADD CONSTRAINT PUBLIC.FK_ORDPOS2ORDER FOREIGN KEY(order_id) REFERENCES PUBLIC.RESTAURANTORDER(id) NOCHECK; -ALTER TABLE PUBLIC.ORDERPOSITION ADD CONSTRAINT PUBLIC.FK_ORDPOS2COOK FOREIGN KEY(cook_id) REFERENCES PUBLIC.STAFFMEMBER(id) NOCHECK; -ALTER TABLE PUBLIC.BILL_ORDERPOSITION ADD CONSTRAINT PUBLIC.FK_BILLORDPOS2BILL FOREIGN KEY(bill_id) REFERENCES PUBLIC.BILL(id) NOCHECK; -ALTER TABLE PUBLIC.BILL_ORDERPOSITION ADD CONSTRAINT PUBLIC.FK_BILLORDPOS2ORDPOS FOREIGN KEY(orderPositions_ID) REFERENCES PUBLIC.ORDERPOSITION(id) NOCHECK; -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.FK_OFFER2SIDEDISH FOREIGN KEY(sideDish_id) REFERENCES PUBLIC.PRODUCT(id) NOCHECK; -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.FK_OFFER2MEAL FOREIGN KEY(meal_id) REFERENCES PUBLIC.PRODUCT(id) NOCHECK; -ALTER TABLE PUBLIC.OFFER ADD CONSTRAINT PUBLIC.FK_OFFER2DRINK FOREIGN KEY(drink_id) REFERENCES PUBLIC.PRODUCT(id) NOCHECK; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0002_1__Delete_and_add_test_data.sql b/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0002_1__Delete_and_add_test_data.sql deleted file mode 100644 index 5425bd7c7..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0002_1__Delete_and_add_test_data.sql +++ /dev/null @@ -1,16 +0,0 @@ -SET FOREIGN_KEY_CHECKS=0; - -DELETE FROM RESTAURANTTABLE; -DELETE FROM RESTAURANTORDER; -DELETE FROM PRODUCT; -DELETE FROM OFFER; -DELETE FROM ORDERPOSITION; -DELETE FROM BILL; -DELETE FROM STAFFMEMBER; - -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (0, 'chief', 3, 'Charly', 'Chief', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (1, 'cook', 0, 'Carl', 'Cook', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (2, 'waiter', 1, 'Willy', 'Waiter', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (3, 'barkeeper', 2, 'Bianca', 'Barkeeper', 0); - -SET FOREIGN_KEY_CHECKS=1; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0003_1__Delete_data.sql b/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0003_1__Delete_data.sql deleted file mode 100644 index bbffc588a..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/test-data/V0003_1__Delete_data.sql +++ /dev/null @@ -1 +0,0 @@ -DELETE FROM BINARYOBJECT; \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringIntegrationTest.java b/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringIntegrationTest.java deleted file mode 100644 index 6e1ad3440..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringIntegrationTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import javax.inject.Inject; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.runner.RunWith; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.annotation.DirtiesContext.ClassMode; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; -import org.springframework.transaction.annotation.Transactional; - -/** - * - * @author agreul - */ -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class }) -@Transactional -@DirtiesContext(classMode = ClassMode.AFTER_CLASS) -@ActiveProfiles("db-plain") -public abstract class AbstractSpringIntegrationTest extends Assert { - - @Inject - private ConfigurableApplicationContext context; - - private static ConfigurableApplicationContext lastContext; - - /** - * - */ - @After - public void onTearDown() { - - lastContext = this.context; - } - - /** - * - */ - @AfterClass - public static void onClassTearDown() { - - lastContext.close(); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java b/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java deleted file mode 100644 index 6d9d2229e..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.logic.impl; - -import io.oasp.gastronomy.restaurant.general.common.AbstractSpringIntegrationTest; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; -import io.oasp.module.configuration.common.api.ApplicationConfigurationConstants; - -import javax.inject.Inject; - -import org.junit.Test; -import org.springframework.test.context.ContextConfiguration; - -/** - * This is the test-case of {@link Salesmanagement}. - * - * @author hohwille - */ -@ContextConfiguration({ ApplicationConfigurationConstants.BEANS_LOGIC }) -public class SalesManagementTest extends AbstractSpringIntegrationTest { - - @Inject - private Salesmanagement salesManagement; - - /** - * Tests if a Bill is persisted correctly. Special focus is on the mapping of {@link Money} and furthermore the query - * of one of the {@link Money} fields is tested. - */ - @Test - public void testSalesmanagement() { - - TableEto table = new TableEto(); - Long tableId = 1L; - table.setId(tableId); - OrderEto order = this.salesManagement.saveOrder(table); - assertEquals(tableId, Long.valueOf(order.getTableId())); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/app/service/beans-test-service-rest.xml b/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/app/service/beans-test-service-rest.xml deleted file mode 100644 index bba463d3b..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/app/service/beans-test-service-rest.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/env/application.properties b/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/env/application.properties deleted file mode 100644 index 0a28524f9..000000000 --- a/oasp4j-samples/oasp4j-sample-core/src/test/resources/config/env/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -# ---------------------------------------------------------------------------- -# This file contains the environment specific properties of the application. -# It should contain only parameters managed by system operations. -# -# It shall never be included in the deliverable of the application (WAR file). -# Therefore it is excluded during the build process with Maven. -# On the actual environment this file shall be provided with the according -# and correct settings in the following location of tomcat (CATALINA_HOME): -# lib/config/env/application.properties -# ---------------------------------------------------------------------------- - -# -database.user.login = sa -database.user.password = -database.url = jdbc:h2:./target/.sample;INIT=create schema if not exists public -database.migration.auto = true -database.migration.clean = true - -database.hibernate.hbm2ddl.auto = update \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/pom.xml b/oasp4j-samples/oasp4j-sample-server-integration/pom.xml deleted file mode 100644 index 05a49995e..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/pom.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-samples - dev-SNAPSHOT - - io.oasp.java.samples - oasp4j-sample-server-integration - ${project.artifactId} - Integration tests for OASP4J sample app. - - - - org.apache.cxf - cxf-rt-rs-client - - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - - - - org.apache.httpcomponents - httpclient - - - - org.apache.httpcomponents - httpcore - 4.3.2 - - - - io.oasp.java.modules - oasp4j-test - test - - - - ${project.groupId} - oasp4j-sample-core - ${project.version} - jar - - - - ${project.groupId} - oasp4j-sample-server - ${project.version} - war - - - - - - - src/main/resources - true - - - - - src/test/resources - true - - - - - org.codehaus.cargo - cargo-maven2-plugin - 1.2.2 - - - tomcat7x - - http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.30/bin/apache-tomcat-7.0.30.zip - - - - standalone - - ${oasp.http.port} - - - - ${project.build.testOutputDirectory}/config/tomcat/tomcat-users.xml - conf - - - ${project.build.testOutputDirectory}/config/env/application.properties - shared/classes/config/env - - - - - ${project.groupId} - oasp4j-sample-server - - oasp4j-sample-server - - war - - - - - - - start-server - process-test-classes - - start - - - - stop-server - post-integration-test - - stop - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java deleted file mode 100644 index f8fabc57d..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/RestUrls.java +++ /dev/null @@ -1,508 +0,0 @@ -package io.oasp.gastronomy.restaurant.test.config; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; - -/** - * All Service Urls - * - * @author arklos - */ -public interface RestUrls { - - /** - * SalesManagement Urls - * - * @author arklos - */ - public static class SalesManagement { - /** - * - */ - public final static String SALES_MANAGEMENT_URL = "/services/rest/salesmanagement/v1"; - - /** - * Order Urls - * - * @author arklos - */ - public static class Order { - /** - * - */ - public final static String ORDER_URL = SALES_MANAGEMENT_URL + "/order"; - - /** - * @param orderId The orderId of the request - * @return URL to get the order for the specified Id - */ - public static final String getFindOrderURL(Long orderId) { - - return ORDER_URL + "/" + orderId; - } - - /** - */ - /** - * @return Url - */ - public static final String getFindOrdersURL() { - - return ORDER_URL + "/"; - } - - /** - * @return URL to create a Order - */ - public static final String getCreateOrderURL() { - - return ORDER_URL + "/"; - } - - /** - * @return URL to create a OrderPosition - */ - public static final String getCreateOrderPositionURL() { - - return ORDER_URL + "position/"; - } - - /** - * @param orderPositionId Id of the position - * @return URL to get the OrderPosition - */ - public static final String getGetOrderPositionURL(Long orderPositionId) { - - return ORDER_URL + "position/" + orderPositionId; - } - - /** - * @return URL to get the OrderPosition - */ - public static final String getUpdateOrderPositionURL() { - - return ORDER_URL + "position/"; - } - - /** - * @param orderId Order of the position - * @param orderPositionId Id of the position - * @param state New state - * @return URL to get the OrderPosition - */ - public static final String getMarkOrderPositionAsURL(Long orderId, Long orderPositionId, OrderPositionState state) { - - return ORDER_URL + orderId + "/position/" + orderPositionId + "/" + state; - } - - /** - * @param orderId Id - * @return URL to get the ChangeTable - */ - public static final String getChangeTableURL(Long orderId) { - - return ORDER_URL + "/" + orderId + "/"; - } - - } - - /** - * Bill Urls - * - * @author arklos - */ - public static class Bill { - /** - * - */ - public final static String BILL_URL = SALES_MANAGEMENT_URL + "/bill"; - - /** - * @param billId Id of the bill - * @return URL to get the bill - */ - public static final String getGetBillURL(Long billId) { - - return BILL_URL + "/" + billId; - } - - /** - * @param billId Id of the bill - * @return URL for payments - */ - public static final String getDoPaymentURL(Long billId) { - - return BILL_URL + "/" + billId + "/payment"; - } - - /** - * @param tip Tip - * @return URL to create Bills - */ - public static final String getCreateBillURL(Money tip) { - - return BILL_URL + "/"; - } - - /** - * @param billId Bill id - * @return Url - */ - public static final String deleteBill(Long billId) { - - return getGetBillURL(billId); - } - } - } - - /** - * StaffManagement Urls - * - * @author arklos - */ - public static class StaffManagement { - /** - * - */ - public final static String STAFF_MANAGEMENT_URL = "/services/rest/staffmanagement/v1/staff"; - - /** - * @return Url - */ - public final static String getGetAllStaffMembersUrl() { - - return STAFF_MANAGEMENT_URL + "/"; - } - - /** - * @param login Login - * @return Url - */ - public final static String getGetStaffMemberUrl(String login) { - - return STAFF_MANAGEMENT_URL + "/" + login; - } - - /** - * @param login Login - * @return Url - */ - public final static String getGetStaffMember(String login) { - - return STAFF_MANAGEMENT_URL + "/" + login; - } - - /** - * @param login Login - * @return Url - */ - public final static String getUpdateStaffMember(String login) { - - return STAFF_MANAGEMENT_URL + "/" + login; - } - - /** - * @param login Login - * @return Url - */ - public final static String getDeleteStaffMemberUrl(String login) { - - return STAFF_MANAGEMENT_URL + "/" + login; - } - } - - /** - * Tablemanagement Urls - * - * @author arklos - */ - public static class TableManagement { - /** - * - */ - public final static String TABLE_MANAGEMENT_URL = "/services/rest/tablemanagement/v1"; - - /** - * - */ - public static final String TABLE_URL = TABLE_MANAGEMENT_URL + "/table"; - - /** - * @param id Table Id - * @return Url - */ - public final static String getGetTableUrl(Long id) { - - return TABLE_URL + "/" + id + "/"; - } - - /** - * @return Url - */ - public final static String getAllTablesUrl() { - - return TABLE_URL; - } - - /** - * @return Url - */ - public final static String getCreateTableUrl() { - - return TABLE_URL; - } - - /** - * @param id Table id - * @return Url - */ - public final static String getDeleteTableUrl(Long id) { - - return TABLE_URL + "/" + id; - } - - /** - * @return Url - */ - public static final String getFreeTablesUrl() { - - return TABLE_MANAGEMENT_URL + "/freetables"; - } - - /** - * @param id Table id - * @param newState New state - * @return Url - */ - public final static String markTableAsUrl(Long id, TableState newState) { - - return TABLE_URL + "/" + id + "/marktableas/" + newState; - } - - /** - * @param id Table id - * @return Url - */ - public final static String isTableReleasableUrl(Long id) { - - return TABLE_URL + "/" + id + "/istablereleasable/"; - - } - - } - - /** - * Offermanagement Urls - * - * @author arklos - */ - public static class Offermanagement { - /** - * - */ - public static final String OFFER_MANAGEMENT_URL = "/services/rest/offermanagement/v1"; - - /** - * Offer Urls - * - * @author arklos - */ - public static class Offer { - /** - * - */ - public static final String OFFER_URL = OFFER_MANAGEMENT_URL + "/offer"; - - /** - * @param id Offer id - * @return Url - */ - public final static String getGetOfferUrl(Long id) { - - return OFFER_URL + "/" + id; - } - - /** - * @return Url - */ - public final static String getCreateOfferUrl() { - - return OFFER_URL + "/"; - } - - /** - * @param id Offer id - * @return Url - */ - public final static String getUpdateOfferUrl(Long id) { - - return OFFER_URL + "/" + id; - } - - /** - * @return Url - */ - public final static String getGetAllOffersUrl() { - - return OFFER_URL + "/"; - } - - /** - * @param id Offer id - * @return Url - */ - public static final String getDeleteOfferUrl(Long id) { - - return OFFER_URL + "/" + id; - } - - /** - * @param sortBy {@link OfferSortBy} - * @return Url - */ - public static final String getFilteredOffers(OfferSortBy sortBy) { - - return OFFER_MANAGEMENT_URL + "/sortby/" + sortBy; - } - } - - /** - * Product Urls - * - * @author arklos - */ - public static class Product { - /** - * - */ - public static final String PRODUCT_URL = OFFER_MANAGEMENT_URL + "/product"; - - /** - * @return Url - */ - public static final String getGetAllProductsUrl() { - - return PRODUCT_URL + "/"; - } - - /** - * @return Url - */ - public static final String getCreateProductUrl() { - - return PRODUCT_URL + "/"; - } - - /** - * @return Url - */ - public static final String getGetAllMealsUrl() { - - return PRODUCT_URL + "/meal"; - } - - /** - * @return Url - */ - public static final String getGetAllDrinksUrl() { - - return PRODUCT_URL + "/drink"; - } - - /** - * @return Url - */ - public static final String getGetAllSideDishesUrl() { - - return PRODUCT_URL + "/side"; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getFindProductUrl(Long id) { - - return PRODUCT_URL + "/" + id; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getUpdateProductUrl(Long id) { - - return PRODUCT_URL + "/" + id; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getIsProductInUseByOfferUrl(Long id) { - - return PRODUCT_URL + "/" + id + "/inuse"; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getDeleteProductUrl(Long id) { - - return PRODUCT_URL + "/" + id; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getGetProductPictureUrl(Long id) { - - return PRODUCT_URL + "/" + id + "/picture"; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getSetProductPictureUrl(Long id) { - - return PRODUCT_URL + "/" + id + "/picture"; - } - - /** - * @param id Product id - * @return Url - */ - public static final String getDeleteProductPictureUrl(Long id) { - - return PRODUCT_URL + "/" + id + "/picture"; - } - - /** - * @param sortBy {@link ProductSortBy} - * @return Url - */ - public static final String getFilteredProducts(ProductSortBy sortBy) { - - return PRODUCT_URL + "/sortby/" + sortBy; - } - - /** - * @param id Product id - * @param revision number - * @return Url - */ - public static String getFindProductByRevisionUrl(Long id, Long revision) { - - return PRODUCT_URL + "/" + id + "/" + revision; - } - - } - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/TestData.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/TestData.java deleted file mode 100644 index 247bee5ad..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/config/TestData.java +++ /dev/null @@ -1,584 +0,0 @@ -package io.oasp.gastronomy.restaurant.test.config; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Role; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferState; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillEto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderCto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; -import io.oasp.gastronomy.restaurant.staffmanagement.logic.api.to.StaffMemberEto; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * - * @author arklos - */ -public class TestData { - - /** - * - * @author arklos - */ - public static final class Additional { - - /***/ - public static final TableEto TABLE = createTable(null, 100L, null, TableState.FREE); - - /***/ - public static final MealEto MEAL = createMeal(null, "Hund", null); - - /***/ - public static final SideDishEto SIDE_DISH = createSideDish(null, "Katze", null); - - /***/ - public static final DrinkEto DRINK = createDrink(null, "Waesserchen", null, false); - - /***/ - public static final OfferEto OFFER = createOffer(null, "Hund-Katze-Maus-Menue", OfferState.NORMAL, 1L, 5L, 10L, - null, new Money(6.99)); - - /***/ - public static final OrderCto ORDER = createOrderCto(null, 1L, null, OrderState.CLOSED); - - /***/ - public static final OrderPositionEto ORDER_POSITION = createOrderPosition(null, "Schnitzel-Menü", "mit Ketschup", - OrderPositionState.DELIVERED, 1L, null, new Money(6.99)); - - /***/ - public static final BillEto BILL = createBill(null, true, null, new Money(14.98), new Money(1.4), 3L, 4L); - - /***/ - public static final StaffMemberEto STAFF_MEMEBR = createStaffmember(100L, Role.CHIEF, "Artur", "Chief", 0); - - /***/ - public static final TableEto CHANGED_TABLE_1 = createTable(101L, 1L, 1, TableState.FREE); - - /***/ - public static final MealEto CHANGED_MEAL_1 = createMeal(1L, "Maus", 1); - - /***/ - public static final SideDishEto CHANGED_SIDE_DISH_1 = createSideDish(5L, "Sommep", 1); - - /***/ - public static final DrinkEto CHANGED_DRINK_1 = createDrink(9L, "Waesserchen", 1, false); - - /***/ - public static final OfferEto CHANGED_OFFER_1 = createOffer(1L, "Schnitzel-Menü", OfferState.SPECIAL, 1L, 5L, 10L, - 1, new Money(8.99)); - - /***/ - public static final OrderCto CHANGED_ORDER_1_CTO = createOrderCto(1L, 1L, 1, OrderState.OPEN); - - /***/ - public static final OrderPositionEto CHANGED_ORDER_POSITION_1 = createOrderPosition(1L, "Maus-Menü", "mit Hose", - OrderPositionState.PAYED, 1L, 1, new Money(6.99)); - - /***/ - public static final BillEto CHANGED_BILL_1 = createBill(1L, true, 1, new Money(15.98), new Money(2.3), 1L, 2L); - - /***/ - public static final StaffMemberEto CHANGED_STAFF_MEMEBR_1 = - createStaffmember(0L, Role.CHIEF, "Charles", "Chief", 0); - - } - - /** - * - * @author arklos - */ - public static final class DB { - /***/ - public static final TableEto TABLE_1 = createTable(101L, 1L, 1, TableState.OCCUPIED); - - /***/ - public static final TableEto TABLE_2 = createTable(102L, 2L, 1, TableState.FREE); - - /***/ - public static final TableEto TABLE_3 = createTable(103L, 3L, 1, TableState.FREE); - - /***/ - public static final TableEto TABLE_4 = createTable(104L, 4L, 1, TableState.FREE); - - /***/ - public static final TableEto TABLE_5 = createTable(105L, 5L, 1, TableState.FREE); - - /***/ - public static final MealEto MEAL_1 = createMeal(1L, "Schnitzel", 1); - - /***/ - public static final MealEto MEAL_2 = createMeal(2L, "Goulasch", 1); - - /***/ - public static final MealEto MEAL_3 = createMeal(3L, "Pfifferlinge", 1); - - /***/ - public static final MealEto MEAL_4 = createMeal(4L, "Salat", 1); - - /***/ - public static final SideDishEto SIDE_DISH_1 = createSideDish(5L, "Pommes", 1); - - /***/ - public static final SideDishEto SIDE_DISH_2 = createSideDish(6L, "Reis", 1); - - /***/ - public static final SideDishEto SIDE_DISH_3 = createSideDish(7L, "Brot", 1); - - /***/ - public static final SideDishEto SIDE_DISH_4 = createSideDish(8L, "Knödel", 1); - - /***/ - public static final DrinkEto DRINK_1 = createDrink(9L, "Wasser", 1, false); - - /***/ - public static final DrinkEto DRINK_2 = createDrink(10L, "Cola", 1, false); - - /***/ - public static final DrinkEto DRINK_3 = createDrink(11L, "Bier", 1, false); - - /***/ - public static final DrinkEto DRINK_4 = createDrink(12L, "Wein / Apfelwein", 1, false); - - /***/ - public static final OfferEto OFFER_1 = createOffer(1L, "Schnitzel-Menü", OfferState.NORMAL, 1L, 5L, 10L, 1, - new Money(6.99)); - - /***/ - public static final OfferEto OFFER_2 = createOffer(2L, "Goulasch-Menü", OfferState.NORMAL, 2L, 6L, 11L, 1, - new Money(7.99)); - - /***/ - public static final OfferEto OFFER_3 = createOffer(4L, "Pfifferlinge-Menü", OfferState.NORMAL, 3L, 8L, 12L, 1, - new Money(8.99)); - - /***/ - public static final OfferEto OFFER_4 = createOffer(5L, "Salat-Menü", OfferState.NORMAL, 4L, 7L, 9L, 1, new Money( - 5.99)); - - /***/ - public static final OrderEto ORDER_1 = createOrder(1L, 1L, 1, OrderState.CLOSED); - - /***/ - public static final OrderPositionEto ORDER_POSITION_1 = createOrderPosition(1L, "Schnitzel-Menü", "mit Ketschup", - OrderPositionState.DELIVERED, 1L, 1, new Money(6.99)); - - /***/ - public static final OrderPositionEto ORDER_POSITION_2 = createOrderPosition(2L, "Goulasch-Menü", "", - OrderPositionState.DELIVERED, 1L, 1, new Money(7.99)); - - /***/ - public static final OrderPositionEto ORDER_POSITION_3 = createOrderPosition(3L, "Pfifferlinge-Menü", "", - OrderPositionState.DELIVERED, 1L, 1, new Money(8.99)); - - /***/ - public static final OrderPositionEto ORDER_POSITION_4 = createOrderPosition(4L, "Salat-Menü", "", - OrderPositionState.DELIVERED, 1L, 1, new Money(5.99)); - - /***/ - public static final BillEto BILL_1 = createBill(1L, false, 1, new Money(14.98), new Money(1.3), 1L, 2L); - - /***/ - public static final BillEto BILL_2 = createBill(2L, true, 1, new Money(14.98), new Money(1.4), 3L, 4L); - - /***/ - public static final StaffMemberEto STAFF_MEMEBR_1 = createStaffmember(0L, Role.CHIEF, "Charly", "Chief", 0); - - /***/ - public static final StaffMemberEto STAFF_MEMEBR_2 = createStaffmember(1L, Role.COOK, "Carl", "Cook", 0); - - /***/ - public static final StaffMemberEto STAFF_MEMEBR_3 = createStaffmember(2L, Role.WAITER, "Willy", "Waiter", 0); - - /***/ - public static final StaffMemberEto STAFF_MEMEBR_4 = createStaffmember(3L, Role.BARKEEPER, "Bianca", "Barkeeper", 0); - - /***/ - public static final List ALL_STAFF_MEMBER = new LinkedList<>(); - - /***/ - public static final List ALL_BILLS = new LinkedList<>(); - - /***/ - public static final List ALL_ORDER_POSITIONS = new LinkedList<>(); - - /***/ - public static final List ALL_ORDERS = new LinkedList<>(); - - /***/ - public static final List ALL_OFFERS = new LinkedList<>(); - - /***/ - public static final List ALL_TABLES = new LinkedList<>(); - - /***/ - public static final List ALL_MEALS = new LinkedList<>(); - - /***/ - public static final List ALL_SIDE_DISHES = new LinkedList<>(); - - /***/ - public static final List ALL_DRINKS = new LinkedList<>(); - - /***/ - public static final List ALL_PRODUCTS = new LinkedList<>(); - - // /***/ - // public static final StaffMemberEto[] ALL_STAFF_MEMBERS = { STAFF_MEMEBR_1, STAFF_MEMEBR_2, STAFF_MEMEBR_3, - // STAFF_MEMEBR_4 }; - // - // /***/ - // public static final BillEto[] ALL_BILLS = { BILL_1, BILL_2 }; - // - // /***/ - // public static final OrderPositionEto[] ALL_ORDER_POSITIONS = { ORDER_POSITION_1, ORDER_POSITION_2, - // ORDER_POSITION_3, ORDER_POSITION_4 }; - // - // /***/ - // public static final OrderEto[] ALL_ORDERS = { ORDER_1 }; - // - // /***/ - // public static final OfferEto[] ALL_OFFERS = { OFFER_1, OFFER_2, OFFER_3, OFFER_4 }; - // - // /***/ - // public static final TableEto[] ALL_TABLES = { TABLE_1, TABLE_2, TABLE_3, TABLE_4, TABLE_5 }; - // - // /***/ - // public static final MealEto[] ALL_MEALS = { MEAL_1, MEAL_2, MEAL_3, MEAL_4 }; - // - // /***/ - // public static final SideDishEto[] ALL_SIDE_DISHES = { SIDE_DISH_1, SIDE_DISH_2, SIDE_DISH_3, SIDE_DISH_4 }; - // - // /***/ - // public static final DrinkEto[] ALL_DRINKS = { DRINK_1, DRINK_2, DRINK_3, DRINK_4 }; - // - // /***/ - // public static final ProductEto[] ALL_PRODUCTS = { MEAL_1, MEAL_2, MEAL_3, MEAL_4, SIDE_DISH_1, SIDE_DISH_2, - // SIDE_DISH_3, SIDE_DISH_4, DRINK_1, DRINK_2, DRINK_3, DRINK_4 }; - - /** - * Exports DB Data to outputfile - * - * @param file Outputfile - */ - public static final void exportData(String file) { - - try { - BufferedWriter writer = new BufferedWriter(new FileWriter(file)); - init(); - writer.write("SET REFERENTIAL_INTEGRITY FALSE;\n\n"); - writer.write("TRUNCATE TABLE STAFFMEMBER;\n"); - writer.write("TRUNCATE TABLE BILL_ORDERPOSITION;\n"); - writer.write("TRUNCATE TABLE OFFER;\n"); - writer.write("TRUNCATE TABLE RestaurantTable;\n"); - writer.write("TRUNCATE TABLE BILL;\n"); - writer.write("TRUNCATE TABLE ORDERPOSITION;\n"); - writer.write("TRUNCATE TABLE TABLEORDER;\n"); - writer.write("TRUNCATE TABLE PRODUCT;\n\n"); - writer.write("SET REFERENTIAL_INTEGRITY TRUE;\n\n"); - - for (TableEto e : ALL_TABLES) { - writer.write("INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( " - + getCsv(e.getId(), e.getNumber(), e.getModificationCounter(), - getPosition(e.getState(), TableState.values())) + " );\n"); - } - - writer.write("\n"); - - for (MealEto e : ALL_MEALS) { - writer.write("INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( " - + getCsv(e.getId(), "Meal", e.getDescription(), e.getModificationCounter()) + " );\n"); - } - - writer.write("\n"); - - for (SideDishEto e : ALL_SIDE_DISHES) { - writer.write("INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( " - + getCsv(e.getId(), "SideDish", e.getDescription(), e.getModificationCounter()) + " );\n"); - } - - writer.write("\n"); - - for (DrinkEto e : ALL_DRINKS) { - writer.write("INSERT INTO PRODUCT (id, dtype, description, modificationCounter, alcoholic) VALUES ( " - + getCsv(e.getId(), "Drink", e.getDescription(), e.getModificationCounter(), e.isAlcoholic()) + " );\n"); - } - - writer.write("\n"); - - for (OfferEto e : ALL_OFFERS) { - writer - .write("INSERT INTO OFFER (id, description, state, meal_id, sidedish_id, drink_id, modificationCounter, currentprice) VALUES ( " - + getCsv(e.getId(), e.getDescription(), getPosition(e.getState(), OfferState.values()), - e.getMealId(), e.getSideDishId(), e.getDrinkId(), e.getModificationCounter(), e.getPrice() - .getValue()) + " );\n"); - } - - writer.write("\n"); - - for (OrderEto e : ALL_ORDERS) { - writer.write("INSERT INTO TABLEORDER (id, tableid, modificationCounter, state) VALUES ( " - + getCsv(e.getId(), e.getTableId(), e.getModificationCounter(), - getPosition(e.getState(), OrderState.values())) + " );\n"); - } - - writer.write("\n"); - - for (OrderPositionEto e : ALL_ORDER_POSITIONS) { - writer - .write("INSERT INTO ORDERPOSITION (id, offername, comment, state, order_Id, modificationCounter, price) VALUES ( " - + getCsv(e.getId(), e.getOfferName(), e.getComment(), - getPosition(e.getState(), OrderPositionState.values()), e.getOrderId(), - e.getModificationCounter(), e.getPrice().getValue()) + " );\n"); - } - - writer.write("\n"); - - for (BillEto e : ALL_BILLS) { - writer.write("INSERT INTO BILL (id, payed, modificationCounter, totalamount,tip) VALUES ( " - + getCsv(e.getId(), e.isPayed(), e.getModificationCounter(), e.getTotal().getValue(), e.getTip() - .getValue()) + " );\n"); - for (Long id : e.getOrderPositionIds()) { - writer.write("INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES ( " - + getCsv(e.getId(), id) + " );\n"); - } - } - - writer.write("\n"); - - for (StaffMemberEto e : ALL_STAFF_MEMBER) { - writer.write("INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES ( " - + getCsv(e.getId(), e.getLastName().toLowerCase(), getPosition(e.getRole(), Role.values()), - e.getFirstName(), e.getLastName(), e.getModificationCounter()) + " );\n"); - } - writer.flush(); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private static final int getPosition(Object o, Object[] values) { - - for (int i = 0; i < values.length; i++) { - Object e = values[i]; - if (o.equals(e)) { - return i; - } - } - return -1; - } - - private static final String getCsv(Object... values) { - - String csv = ""; - for (Object o : values) { - if (o instanceof String) { - csv += "'" + o + "' , "; - } else { - csv += o + " , "; - } - } - csv = csv.substring(0, csv.length() - 2); - return csv; - } - } - - @SuppressWarnings("javadoc") - public static final OrderEto createOrder(Long id, Long tableid, Integer modificationCounter, OrderState state) { - - OrderEto order = new OrderEto(); - order.setId(id); - order.setTableId(tableid); - if (modificationCounter != null) - order.setModificationCounter(modificationCounter); - order.setState(state); - return order; - } - - @SuppressWarnings("javadoc") - public static final OrderCto createOrderCto(Long id, Long tableid, Integer modificationCounter, OrderState state) { - - OrderCto cto = new OrderCto(); - cto.setOrder(createOrder(id, tableid, modificationCounter, state)); - return cto; - } - - @SuppressWarnings("javadoc") - public static final StaffMemberEto createStaffmember(Long id, Role role, String firstname, String lastname, - Integer modificationCounter) { - - StaffMemberEto member = new StaffMemberEto(); - member.setId(id); - member.setRole(role); - member.setFirstName(firstname); - member.setLastName(lastname); - if (modificationCounter != null) - member.setModificationCounter(modificationCounter); - - return member; - } - - @SuppressWarnings("javadoc") - public static final BillEto createBill(Long id, boolean payed, Integer modificationCounter, Money totalamount, - Money tip, Long... orderPositions) { - - BillEto bill = new BillEto(); - bill.setId(id); - bill.setPayed(payed); - if (modificationCounter != null) - bill.setModificationCounter(modificationCounter); - bill.setTotal(totalamount); - bill.setTip(tip); - if (orderPositions != null) { - bill.setOrderPositionIds(Arrays.asList(orderPositions)); - } - return bill; - } - - @SuppressWarnings("javadoc") - public static final OrderPositionEto createOrderPosition(Long id, String offername, String comment, - OrderPositionState state, Long order_Id, Integer modificationCounter, Money price) { - - OrderPositionEto position = new OrderPositionEto(); - position.setId(id); - position.setOfferName(offername); - position.setComment(comment); - position.setState(state); - position.setOrderId(order_Id); - if (modificationCounter != null) - position.setModificationCounter(modificationCounter); - position.setPrice(price); - return position; - } - - @SuppressWarnings("javadoc") - public static final TableEto createTable(Long id, Long number, Integer modificationCounter, TableState state) { - - TableEto table = new TableEto(); - if (id != null) { - table.setId(id); - } - if (number == null) { - table.setNumber(id); - } else { - table.setNumber(number); - } - if (modificationCounter != null) - table.setModificationCounter(modificationCounter); - table.setState(state); - return table; - } - - @SuppressWarnings("javadoc") - public static final MealEto createMeal(Long id, String description, Integer modificationCounter) { - - MealEto meal = new MealEto(); - meal.setId(id); - meal.setDescription(description); - if (modificationCounter != null) - meal.setModificationCounter(modificationCounter); - return meal; - } - - @SuppressWarnings("javadoc") - public static final SideDishEto createSideDish(Long id, String description, Integer modificationCounter) { - - SideDishEto sideDish = new SideDishEto(); - sideDish.setId(id); - sideDish.setDescription(description); - if (modificationCounter != null) - sideDish.setModificationCounter(modificationCounter); - return sideDish; - } - - @SuppressWarnings("javadoc") - public static final DrinkEto createDrink(Long id, String description, Integer modificationCounter, boolean alcoholic) { - - DrinkEto drink = new DrinkEto(); - drink.setId(id); - drink.setDescription(description); - if (modificationCounter != null) - drink.setModificationCounter(modificationCounter); - drink.setAlcoholic(alcoholic); - return drink; - } - - @SuppressWarnings("javadoc") - public static final OfferEto createOffer(Long id, String description, OfferState state, Long meal_id, - Long sidedish_id, Long drink_id, Integer modificationCounter, Money currentprice) { - - OfferEto offer = new OfferEto(); - offer.setId(id); - offer.setDescription(description); - offer.setState(state); - offer.setMealId(meal_id); - offer.setSideDishId(sidedish_id); - offer.setDrinkId(drink_id); - if (modificationCounter != null) - offer.setModificationCounter(modificationCounter); - offer.setPrice(currentprice); - return offer; - } - - private static boolean initiated = false; - - /***/ - public static final void init() { - - if (!initiated) { - DB.ALL_STAFF_MEMBER.addAll(searchForFields(DB.class, StaffMemberEto.class)); - DB.ALL_BILLS.addAll(searchForFields(DB.class, BillEto.class)); - DB.ALL_ORDER_POSITIONS.addAll(searchForFields(DB.class, OrderPositionEto.class)); - DB.ALL_ORDERS.addAll(searchForFields(DB.class, OrderEto.class)); - DB.ALL_OFFERS.addAll(searchForFields(DB.class, OfferEto.class)); - DB.ALL_TABLES.addAll(searchForFields(DB.class, TableEto.class)); - DB.ALL_MEALS.addAll(searchForFields(DB.class, MealEto.class)); - DB.ALL_SIDE_DISHES.addAll(searchForFields(DB.class, SideDishEto.class)); - DB.ALL_DRINKS.addAll(searchForFields(DB.class, DrinkEto.class)); - DB.ALL_PRODUCTS.addAll(DB.ALL_MEALS); - DB.ALL_PRODUCTS.addAll(DB.ALL_SIDE_DISHES); - DB.ALL_PRODUCTS.addAll(DB.ALL_DRINKS); - initiated = true; - } - } - - @SuppressWarnings("unchecked") - private static final List searchForFields(Class source, Class type) { - - List list = new LinkedList<>(); - - Field[] fields = source.getDeclaredFields(); - - for (Field field : fields) { - if (field.getType().equals(type)) { - try { - list.add((T) field.get(null)); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - - return list; - - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/AppProperties.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/AppProperties.java deleted file mode 100644 index d4a4d5bdf..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/AppProperties.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.oasp.gastronomy.restaurant.test.general; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -/** - * Application properties - * - * @author hahmad, arklos - */ -public class AppProperties { - - private static Properties prop; - - static { - prop = new Properties(); - String propFileName = "config.properties"; - InputStream inputStream = AppProperties.class.getClassLoader().getResourceAsStream(propFileName); - try { - prop.load(inputStream); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** The host of the server to test. */ - public static final String SERVER_HOST = prop.getProperty("server.host"); - - /** The port of the server to test. */ - public static final int SERVER_PORT = Integer.parseInt(prop.getProperty("server.port")); - - /** The URL of the server to test. */ - public static final String SERVER_URL = "http://" + SERVER_HOST + ":" + SERVER_PORT + "/oasp4j-sample-server"; - - /** The URL for the login. */ - public static final String SERVER_URL_LOGIN = SERVER_URL + "/j_spring_security_login"; - - /** The port of the database. */ - public static final int DATABASE_PORT = Integer.parseInt(prop.getProperty("database.port")); - - /** - * Login credentials - * - * @author hahmad, arklos - */ - public static class LoginCredentials { - - /** Login of the default waiter. */ - public static final String WAITER_USERNAME = "waiter"; - - /** Password of the default waiter. */ - public static final String WAITER_PASSWORD = "waiter"; - - /** Login of the default chief. */ - public static final String CHIEF_USERNAME = "chief"; - - /** Password of the default chief. */ - public static final String CHIEF_PASSWORD = "chief"; - - /** Login of the default barkeeper. */ - public static final String BARKEEPER_USERNAME = "barkeeper"; - - /** Password of the default barkeeper. */ - public static final String BARKEEPER_PASSWORD = "barkeeper"; - - /** Login of the default cook. */ - public static final String COOK_USERNAME = "cook"; - - /** Password of the default cook. */ - public static final String COOK_PASSWORD = "cook"; - - /** {@link Map} from login to password. */ - public static final Map USERNAME2PASSWORD_MAP; - static { - USERNAME2PASSWORD_MAP = new HashMap<>(); - USERNAME2PASSWORD_MAP.put(WAITER_USERNAME, WAITER_PASSWORD); - USERNAME2PASSWORD_MAP.put(CHIEF_USERNAME, CHIEF_PASSWORD); - USERNAME2PASSWORD_MAP.put(BARKEEPER_USERNAME, BARKEEPER_PASSWORD); - USERNAME2PASSWORD_MAP.put(COOK_USERNAME, COOK_PASSWORD); - } - - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/ResponseData.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/ResponseData.java deleted file mode 100644 index 63847243b..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/ResponseData.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.oasp.gastronomy.restaurant.test.general.webclient; - -import javax.ws.rs.core.Response; - -/** - * - * This Contrainer class holds data from the serverresponse - * - * @author hahmad, arklos - * @param A tranfered Object - */ -public class ResponseData { - - private T responseObject; - - private Response response; - - private String jsonString; - - /** - * The constructor. - * - * @param responseObject Object that has been transfered from the server - * @param response Server response - * @param jsonString Json response - */ - public ResponseData(T responseObject, Response response, String jsonString) { - - this.responseObject = responseObject; - this.response = response; - this.jsonString = jsonString; - } - - /** - * @param transferObject the transferObject to set - */ - public void setResponseObject(T transferObject) { - - this.responseObject = transferObject; - } - - /** - * @return transferObject - */ - public T getResponseObject() { - - return this.responseObject; - } - - /** - * @return response - */ - public Response getResponse() { - - return this.response; - } - - /** - * @param response the response to set - */ - public void setResponse(Response response) { - - this.response = response; - } - - /** - * @return jsonSting - */ - public String getJsonString() { - - return this.jsonString; - } - - /** - * @param jsonSting the jsonSting to set - */ - public void setJsonString(String jsonSting) { - - this.jsonString = jsonSting; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/WebClientWrapper.java b/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/WebClientWrapper.java deleted file mode 100644 index 41f340957..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/java/io/oasp/gastronomy/restaurant/test/general/webclient/WebClientWrapper.java +++ /dev/null @@ -1,289 +0,0 @@ -package io.oasp.gastronomy.restaurant.test.general.webclient; - -import io.oasp.gastronomy.restaurant.general.service.impl.rest.ApplicationObjectMapperFactory; -import io.oasp.gastronomy.restaurant.test.general.AppProperties; -import io.oasp.gastronomy.restaurant.test.general.AppProperties.LoginCredentials; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.http.NameValuePair; - -import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; - -/** - * - * This client establishes a connection to the server with the specified user. It provides various methods to interact - * with the server. - * - * @author hahmad, arklos - */ -public class WebClientWrapper { - - private WebClient webClient; - - private String username; - - private String password; - - /** - * The constructor. - * - * @param username The username that is used for a login - * @param password The password that is used for a login - */ - public WebClientWrapper(String username, String password) { - - this.username = username; - this.password = password; - initWebClient(); - setCsrfHeader(); - - } - - /** - * The constructor. - * - * @param username The username that is used for a login - */ - public WebClientWrapper(String username) { - - this.username = username; - this.password = LoginCredentials.USERNAME2PASSWORD_MAP.get(username); - initWebClient(); - setCsrfHeader(); - } - - /** - * @return Returns the wrapped webclient - */ - public WebClient getWebClient() { - - return this.webClient; - } - - private void initWebClient() { - - List providers = new ArrayList<>(); - - JacksonJaxbJsonProvider j = new JacksonJaxbJsonProvider(); - j.setMapper(new ApplicationObjectMapperFactory().createInstance()); - providers.add(j); - - WebClient client = WebClient.create(AppProperties.SERVER_URL, providers); - - WebClient.getConfig(client).getRequestContext().put(org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE); - - // set http accept header and type header - client = client.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON); - - client = - client.path("/j_spring_security_login").query("j_username", this.username).query("j_password", this.password); - Response res = client.post(""); - - // TODO Handle when login fails - int status2 = res.getStatus(); - System.out.println("Http status " + status2); - - this.webClient = client; - } - - /** - * @return Returns the username - */ - public String getUsername() { - - return this.username; - } - - /** - * Sets the csrf header - */ - public void setCsrfHeader() { - - String myToken; - this.webClient = this.webClient.replacePath("/services/rest/security/v1/csrftoken/"); - - // Response response = this.webClient.get(); - - String res = this.webClient.get(String.class); - String[] ar = res.replace("{", "").replace("}", "").replace("\"", "").split(","); - - myToken = ar[0].split(":")[1]; - - this.webClient = this.webClient.header("X-CSRF-TOKEN", myToken); - - } - - /** - * Gets the data from an Url and returns a list of ResponseData Objects. - * - * @param Type of the Object that will be transfered from the server - * @param url Url - * @param responseObjectClass Class of the ResponseObject - * @return A list of ServerResonseData Objects - */ - public List> getAll(String url, Class responseObjectClass) { - - return getAll(url, null, responseObjectClass); - } - - /** - * Gets the data from an Url and returns a list of ResponseData Objects. - * - * @param Type of the Object that will be transfered from the server - * @param url Url - * @param params List of parameters that will be added to the query - * @param responseObjectClass Class of the ResponseObject - * @return A list of ServerResonseData Objects - */ - public List> getAll(String url, List params, Class responseObjectClass) { - - List> resultList = new ArrayList<>(); - this.webClient.replacePath(url); - if (params != null) { - for (NameValuePair param : params) { - this.webClient.query(param.getName(), param.getValue()); - } - } - - @SuppressWarnings("unchecked") - Collection getResult = (Collection) this.webClient.getCollection(responseObjectClass); - Response response = this.webClient.get(); - String jsonString = this.webClient.get(String.class); - for (T e : getResult) { - resultList.add(new ResponseData<>(e, response, jsonString)); - } - return resultList; - } - - /** - * - * @param Url Url with the specified item to delte - * @return Server response - */ - public Response delete(String Url) { - - this.webClient.replacePath(Url); - return this.webClient.delete(); - } - - /** - * @param transferObject The Object that will be sent to the server - * @param url Url - * @return Server response - */ - public Response put(String url, Object transferObject) { - - this.webClient.replacePath(url); - return this.webClient.put(transferObject); - } - - /** - * @param A Type of the Object that will be transfered from the server - * @param url Url - * @param transferObjectClass Class of the TransferObject - * @return Server response - */ - public ResponseData get(String url, Class transferObjectClass) { - - this.webClient.replacePath(url); - Response response = this.webClient.get(); - String jsonString = this.webClient.get(String.class); - T transferObject = this.webClient.get(transferObjectClass); - return new ResponseData<>(transferObject, response, jsonString); - - } - - /** - * @param url Url - * @return Server response - */ - public Response get(String url) { - - this.webClient.replacePath(url); - return this.webClient.get(); - - } - - /** - * @param Type of the Object that will be transfered from the server - * @param url Url - * @param transferObject Object to put - * @param responseObjectClass Class of object - * @return Server response - */ - public ResponseData put(String url, Object transferObject, Class responseObjectClass) { - - this.webClient.replacePath(url); - T responseObject = this.webClient.put(transferObject, responseObjectClass); - Response response = this.webClient.put(null); - String jsonString = this.webClient.put(null, String.class); - return new ResponseData<>(responseObject, response, jsonString); - - } - - /** - * @param url Url - * @return Server response - */ - public Response post(String url) { - - return post(url, (Object) null); - } - - /** - * @param url Url - * @param transferObject Object that will be transfered - * @return Server response - */ - public Response post(String url, Object transferObject) { - - this.webClient.replacePath(url); - return this.webClient.post(transferObject); - } - - /** - * @param Type of the Object that will be transfered from the server - * @param url Url - * @param responseObjectClass Class of the return type - * @return Server response - */ - public ResponseData post(String url, Class responseObjectClass) { - - this.webClient.replacePath(url); - Response response = this.webClient.post(null); - String jsonString = this.webClient.post(null, String.class); - T responseObject = this.webClient.post(null, responseObjectClass); - return new ResponseData<>(responseObject, response, jsonString); - } - - /** - * @param Type for response - * @param url Url - * @param transferObject Object to put - * @param responseObjectClass Class of object - * @return Server response - */ - public ResponseData post(String url, Object transferObject, Class responseObjectClass) { - - this.webClient.replacePath(url); - T responseObject = this.webClient.post(transferObject, responseObjectClass); - Response response = this.webClient.post(null); - String jsonString = this.webClient.post(null, String.class); - return new ResponseData<>(responseObject, response, jsonString); - } - - public T post(Object body, String url, Class responseObjectClass) { - - this.webClient.replacePath(url); - T responseObject = this.webClient.post(body, responseObjectClass); - return responseObject; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/main/resources/config.properties b/oasp4j-samples/oasp4j-sample-server-integration/src/main/resources/config.properties deleted file mode 100644 index d3197c6ce..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/main/resources/config.properties +++ /dev/null @@ -1,3 +0,0 @@ -server.host=127.0.0.1 -server.port=${oasp.http.port} -database.port=${oasp.db.port} \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/AbstractDBRollbackTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/AbstractDBRollbackTest.java deleted file mode 100644 index 953447d72..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/AbstractDBRollbackTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.oasp; - -import io.oasp.gastronomy.restaurant.test.config.TestData; -import io.oasp.gastronomy.restaurant.test.general.AppProperties; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -import org.h2.tools.RunScript; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; - -/** - * Abstract class that rolls back the Database after each test - * - * @author arklos - */ -public class AbstractDBRollbackTest { - - /** - * Connection to the Database - */ - protected static Connection conn; - - /** - * The constructor. - */ - public AbstractDBRollbackTest() { - - TestData.init(); - TestData.DB.exportData("testdataexport.sql"); - } - - @SuppressWarnings("javadoc") - @BeforeClass - public static void setUp() throws ClassNotFoundException, SQLException { - - Class.forName("org.h2.Driver"); - Class.forName(TestData.class.getName()); - conn = - DriverManager.getConnection("jdbc:h2:tcp://localhost:" + AppProperties.DATABASE_PORT - + "/restaurant-db;INIT=create schema if not exists public", "sa", ""); - } - - @SuppressWarnings("javadoc") - @Before - public void reinit() throws SQLException, FileNotFoundException { - - RunScript.execute(conn, new FileReader("testdataexport.sql")); - } - - @SuppressWarnings("javadoc") - @AfterClass - public static void close() throws SQLException { - - conn.close(); - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractRestServiceTest.java deleted file mode 100644 index 69ea1c24f..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractRestServiceTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import io.oasp.gastronomy.restaurant.general.dataaccess.base.DatabaseMigrator; -import io.oasp.gastronomy.restaurant.test.general.AppProperties.LoginCredentials; -import io.oasp.gastronomy.restaurant.test.general.webclient.WebClientWrapper; -import io.oasp.module.configuration.common.api.ApplicationConfigurationConstants; - -import javax.inject.Inject; -import javax.persistence.EntityManager; - -import org.junit.Before; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; -import org.springframework.transaction.support.TransactionTemplate; - -/** - * Contains reusable test features for rest service tests. Before each test execution the database will be wiped and - * users will be inserted. - * - * @author mbrunnli - * @author jmetzler - */ -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class }) -@ContextConfiguration({ ApplicationConfigurationConstants.BEANS_DATA_ACCESS, -"classpath:/config/app/dataaccess/beans-db-connector.xml" }) -@ActiveProfiles({ "integrationTest", "db-plain" }) -public abstract class AbstractRestServiceTest { - - /** - * WebClientWrapper with access rights of the role waiter. - */ - protected WebClientWrapper waiter = new WebClientWrapper(LoginCredentials.WAITER_USERNAME, - LoginCredentials.WAITER_PASSWORD); - - /** - * WebClientWrapper with access rights of the role chief. - */ - protected WebClientWrapper chief = new WebClientWrapper(LoginCredentials.CHIEF_USERNAME, - LoginCredentials.CHIEF_PASSWORD); - - @Inject - private DatabaseMigrator flyway; - - /** - * @param flyway the DatabaseMigrator to set - */ - public void setFlyway(DatabaseMigrator flyway) { - - this.flyway = flyway; - } - - /** - * The {@link EntityManager}. - */ - @Autowired - public EntityManager entityManager; - - /** - * The {@link TransactionTemplate}. - */ - @Autowired - public TransactionTemplate transactionTemplate; - - /** - * Clear DB and migrate to the latest migration, including test data. - */ - @Before - public void setup() { - - this.flyway.migrate(); - - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/P.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/P.java deleted file mode 100644 index e4266f639..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/P.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common; - -/** - * Functional interface for testdata builder pattern - * - * @author mbrunnli - */ -public interface P { - - public void apply(T target); -} \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/SecurityRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/SecurityRestServiceTest.java deleted file mode 100644 index b4475abed..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/general/common/SecurityRestServiceTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import io.oasp.gastronomy.restaurant.general.common.api.to.UserDetailsClientTo; -import io.oasp.gastronomy.restaurant.test.general.AppProperties; -import io.oasp.gastronomy.restaurant.test.general.webclient.ResponseData; -import io.oasp.gastronomy.restaurant.test.general.webclient.WebClientWrapper; - -import org.junit.Assert; -import org.junit.Test; - -/** - * Class to test security features. - * - * @author jmetzler - */ -public class SecurityRestServiceTest { - - /** - * Login and check if current user is the one logged in. - */ - @Test - public void loginTest() { - - String login = "chief"; - WebClientWrapper user = new WebClientWrapper(login); - - ResponseData response = - user.get(AppProperties.SERVER_URL + "/services/rest/security/v1/currentuser/", UserDetailsClientTo.class); - - Assert.assertEquals(login, response.getResponseObject().getName()); - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java deleted file mode 100644 index 1a1594c37..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/services/OffermanagementRestServiceTest.java +++ /dev/null @@ -1,340 +0,0 @@ -package io.oasp.gastronomy.restaurant.offermanagement.services; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import io.oasp.gastronomy.restaurant.general.common.AbstractRestServiceTest; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferState; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.test.config.RestUrls; -import io.oasp.gastronomy.restaurant.test.config.TestData; -import io.oasp.gastronomy.restaurant.test.config.TestData.Additional; -import io.oasp.gastronomy.restaurant.test.config.TestData.DB; -import io.oasp.gastronomy.restaurant.test.general.webclient.ResponseData; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; - -import javax.ws.rs.core.Response; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Offermanagement rest service test - * - * @author arklos - */ -public class OffermanagementRestServiceTest extends AbstractRestServiceTest { - - /** - * Test CRUD functionality of offer. - */ - @Test - public void crudOfferTest() { - - // get all offers - List> offers = - this.waiter.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); - - // get unused offer description - List offerDescriptions = new ArrayList<>(); - for (ResponseData responseData : offers) { - offerDescriptions.add(responseData.getResponseObject().getDescription()); - } - int number = 1; - String myDescription = "Schnitzel-Menü"; - while (offerDescriptions.contains(myDescription + number)) { - number += 1; - } - myDescription += number; - offerDescriptions.add(myDescription); - - Long mealId = null; - Long drinkId = createDrink().getId(); - Long sidedishId = null; - - // create a new offer - OfferEto createdOffer = - this.chief.post(TestData.createOffer(null, myDescription, OfferState.NORMAL, mealId, sidedishId, drinkId, 0, - new Money(new BigDecimal(2.5))), RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); - // get the created offer - ResponseData offer = - this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); - - Assert.assertNotNull(offer.getResponseObject()); - Assert.assertEquals(createdOffer.getDescription(), offer.getResponseObject().getDescription()); - Assert.assertEquals(createdOffer.getState(), offer.getResponseObject().getState()); - - // update offer - OfferState newState = OfferState.SOLDOUT; - createdOffer.setState(newState); - OfferEto updatedOffer = - this.chief.post(createdOffer, RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); - - Assert.assertEquals(newState, updatedOffer.getState()); - - // delete created offer - Response deleteResponse = this.chief.delete(RestUrls.Offermanagement.Offer.getDeleteOfferUrl(createdOffer.getId())); - Assert.assertEquals(deleteResponse.getStatus(), 204); - - // check if offer is deleted - ResponseData getDeletedOfferResponse = - this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(createdOffer.getId()), OfferEto.class); - Assert.assertNull(getDeletedOfferResponse.getResponseObject()); - - } - - /** - * Create and persist a {@link DrinkEto}. - * - * @return the DrinkEto - */ - public DrinkEto createDrink() { - - ProductEto drink = TestData.createDrink(null, "Wasser", null, false); - DrinkEto response = this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); - return response; - - } - - /** - * Test get offer - */ - @Test - @Ignore - public void getOfferTest() { - - Long id = DB.OFFER_1.getId(); - ResponseData offer = this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); - // assertThat(offer.getResponse().getStatus(), is(200)); - assertThat(offer.getResponseObject().getId(), is(id)); - - id = TestData.DB.OFFER_2.getId(); - offer = this.waiter.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); - // assertThat(offer.getResponse().getStatus(), is(200)); - assertThat(offer.getResponseObject().getId(), is(id)); - - } - - /** - * Test update offer - */ - @Test - @Ignore - public void updateOfferTest() { - - Long id = Additional.CHANGED_OFFER_1.getId(); - this.chief.put(RestUrls.Offermanagement.Offer.getUpdateOfferUrl(id), Additional.CHANGED_OFFER_1); - ResponseData offer = this.chief.get(RestUrls.Offermanagement.Offer.getGetOfferUrl(id), OfferEto.class); - assertThat(offer.getResponse().getStatus(), is(200)); - assertThat(offer.getResponseObject().getName(), is(Additional.CHANGED_OFFER_1.getName())); - } - - /** - * Test get all offer - */ - @Test - public void getAllOffersTest() { - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); - // assertThat(offer.size(), is(TestData.DB.ALL_OFFERS.size())); - for (ResponseData responseData : offer) { - assertThat(responseData.getResponse().getStatus(), is(200)); - } - } - - /** - * Test create product - */ - @Test - @Ignore - public void createProduct() { - - this.chief.post(RestUrls.Offermanagement.Product.getCreateProductUrl(), TestData.Additional.MEAL); - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllProductsUrl(), ProductEto.class); - assertThat(offer.size(), is(DB.ALL_PRODUCTS.size() + 1)); - } - - /** - * Test get all products - */ - @Test - public void getAllProductsTest() { - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllProductsUrl(), ProductEto.class); - // assertThat(offer.size(), is(DB.ALL_PRODUCTS.size())); - for (ResponseData responseData : offer) { - assertThat(responseData.getResponse().getStatus(), is(200)); - } - } - - /** - * Test get all meals - */ - @Test - @Ignore - public void getAllMealsTest() { - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllMealsUrl(), MealEto.class); - // assertThat(offer.size(), is(DB.ALL_MEALS.size())); - for (ResponseData responseData : offer) { - assertThat(responseData.getResponse().getStatus(), is(200)); - } - } - - /** - * Test get all drinks - */ - @Test - public void getAllDrinksTest() { - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllDrinksUrl(), DrinkEto.class); - // assertThat(offer.size(), is(DB.ALL_DRINKS.size())); - for (ResponseData responseData : offer) { - assertThat(responseData.getResponse().getStatus(), is(200)); - } - } - - /** - * Test get all sidedishes - */ - @Test - public void getAllSideDishesTest() { - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getGetAllSideDishesUrl(), SideDishEto.class); - // assertThat(offer.size(), is(DB.ALL_SIDE_DISHES.size())); - for (ResponseData responseData : offer) { - assertThat(responseData.getResponse().getStatus(), is(200)); - } - } - - /** - * Test delete offer - */ - @Test - @Ignore - public void deleteOfferTest() { - - List> offers = - this.chief.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); - - this.chief.delete(RestUrls.Offermanagement.Offer.getDeleteOfferUrl(DB.OFFER_1.getId())); - offers = this.chief.getAll(RestUrls.Offermanagement.Offer.getGetAllOffersUrl(), OfferEto.class); - assertThat(offers.size(), is(DB.ALL_OFFERS.size() - 1)); - } - - /** - * Test find product - */ - @Test - public void findProductTest() { - - Long drinkId = createDrink().getId(); - ResponseData offer = - this.waiter.get(RestUrls.Offermanagement.Product.getFindProductUrl(drinkId), ProductEto.class); - assertThat(offer.getResponse().getStatus(), is(200)); - assertThat(offer.getResponseObject().getId(), is(drinkId)); - - offer = this.waiter.get(RestUrls.Offermanagement.Product.getFindProductUrl(drinkId + 1), ProductEto.class); - Assert.assertNull(offer.getResponseObject()); - - } - - /** - * Test find product - */ - @Test - public void findProductByRevisionTest() { - - // create drink - ProductEto drink = TestData.createDrink(null, "Wasser", null, false); - DrinkEto createdDrink = - this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); - // change drink - createdDrink.setDescription("changed description"); - this.chief.post(createdDrink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); - - Long revision = 1L; - ResponseData revisionedProductResponse = - this.waiter.get(RestUrls.Offermanagement.Product.getFindProductByRevisionUrl(createdDrink.getId(), revision), - DrinkEto.class); - DrinkEto revisionedProduct = revisionedProductResponse.getResponseObject(); - Assert.assertEquals(revision.longValue(), revisionedProduct.getRevision().longValue()); - - } - - /** - * Test update product - */ - @Test - public void updateProductTest() { - - DrinkEto drink = TestData.createDrink(null, "Wasser", null, false); - DrinkEto productToUpdate = - this.chief.post(drink, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); - productToUpdate.setName(drink.getName() + "2"); - this.chief.post(productToUpdate, RestUrls.Offermanagement.Product.getCreateProductUrl(), DrinkEto.class); - ResponseData product = - this.chief.get(RestUrls.Offermanagement.Product.getFindProductUrl(productToUpdate.getId()), ProductEto.class); - - assertThat(product.getResponse().getStatus(), is(200)); - assertThat(product.getResponseObject().getName(), is(productToUpdate.getName())); - } - - /** - * Test is product in use - */ - @Test - public void isProductInUseTest() { - - Long drinkId = createDrink().getId(); - this.chief.post(TestData.createOffer(null, "some description", OfferState.NORMAL, null, null, drinkId, 0, - new Money(new BigDecimal(2.5))), RestUrls.Offermanagement.Offer.getCreateOfferUrl(), OfferEto.class); - ResponseData isproductInUse = - this.waiter.get(RestUrls.Offermanagement.Product.getIsProductInUseByOfferUrl(drinkId), Boolean.class); - assertThat(isproductInUse.getResponseObject(), is(true)); - } - - /** - * Test is get filtered offers - */ - // @Test - public void getFilteredOffersTest() { - - // TODO: Clearify how this call works and write a proper test - OfferSortBy sortBy = new OfferSortBy(); - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Offer.getFilteredOffers(sortBy), OfferEto.class); - assertThat(offer.size(), is(DB.ALL_OFFERS.size())); - } - - /** - * Test is get filtered offers - */ - // @Test - public void getFilteredProductsTest() { - - // TODO: Clearify how this call works and write a proper test - ProductSortBy sortBy = new ProductSortBy(); - - List> offer = - this.waiter.getAll(RestUrls.Offermanagement.Product.getFilteredProducts(sortBy), ProductEto.class); - assertThat(offer.size(), is(DB.ALL_PRODUCTS.size())); - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/services/SalesManagementRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/services/SalesManagementRestServiceTest.java deleted file mode 100644 index 4ef6384ea..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/services/SalesManagementRestServiceTest.java +++ /dev/null @@ -1,344 +0,0 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.services; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import io.oasp.gastronomy.restaurant.general.common.AbstractRestServiceTest; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillCto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillEto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.CreditCardPaymentData; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderCto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; -import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.PaymentData; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; -import io.oasp.gastronomy.restaurant.test.config.RestUrls; -import io.oasp.gastronomy.restaurant.test.config.TestData; -import io.oasp.gastronomy.restaurant.test.config.TestData.Additional; -import io.oasp.gastronomy.restaurant.test.config.TestData.DB; -import io.oasp.gastronomy.restaurant.test.general.webclient.ResponseData; - -import java.math.BigDecimal; -import java.util.LinkedList; -import java.util.List; - -import javax.ws.rs.core.Response; - -import org.apache.http.NameValuePair; -import org.apache.http.message.BasicNameValuePair; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Test sales management rest service - * - * @author arklos - */ -public class SalesManagementRestServiceTest extends AbstractRestServiceTest { - - /** - * Test get order service - */ - @Test - @Ignore - public void getOrderTest() { - - Long id = DB.ORDER_1.getId(); - ResponseData order = this.waiter.get(RestUrls.SalesManagement.Order.getFindOrderURL(id), OrderEto.class); - assertThat(order.getResponseObject().getId(), is(id)); - } - - /** - * Test find all orders service - */ - @Test - @Ignore - public void findAllOrdersTest() { - - String tableId = "" + DB.TABLE_1.getId(); - - List> allOrders = - this.waiter.getAll(RestUrls.SalesManagement.Order.getFindOrdersURL(), OrderCto.class); - assertThat(allOrders.size(), is(DB.ALL_ORDERS.size())); - - List params = new LinkedList<>(); - params.add(new BasicNameValuePair("tableId", tableId)); - allOrders = this.waiter.getAll(RestUrls.SalesManagement.Order.getFindOrdersURL(), params, OrderCto.class); - assertThat(allOrders.size(), is(1)); - - params.clear(); - params.add(new BasicNameValuePair("state", TableState.OCCUPIED.toString())); - allOrders = this.waiter.getAll(RestUrls.SalesManagement.Order.getFindOrdersURL(), params, OrderCto.class); - assertThat(allOrders.size(), is(1)); - } - - /** - * Test update order service - */ - @Test - @Ignore - public void updateOrderTest() { - - String url = RestUrls.SalesManagement.Order.getFindOrderURL(Additional.CHANGED_ORDER_1_CTO.getOrder().getId()); - this.chief.put(url, Additional.CHANGED_ORDER_1_CTO.getOrder()); - ResponseData orderEto = this.waiter.get(url, OrderEto.class); - assertThat(orderEto.getResponseObject().getState(), is(Additional.CHANGED_ORDER_1_CTO.getOrder().getState())); - } - - /** - * Test the createOrder rest service - */ - @Test - @Ignore - public void createOrder() { - - this.chief.post(RestUrls.SalesManagement.Order.getCreateOrderURL(), Additional.ORDER); - List> allOrders = - this.waiter.getAll(RestUrls.SalesManagement.Order.getFindOrdersURL(), OrderCto.class); - assertThat(allOrders.size(), is(DB.ALL_ORDERS.size() + 1)); - - } - - /** - * Test the createOrderPostion rest service - */ - // @Test - public void createOrderPosition() { - - OfferEto offer = Additional.OFFER; - // the only way to get the newly created orderPosition is at the point. But it crashes - // TODO: Investigate the error and fix it - @SuppressWarnings("unused") - ResponseData position = - this.chief.post(RestUrls.SalesManagement.Order.getCreateOrderPositionURL(), offer, OrderPositionEto.class); - - } - - /** - * Test the get order position service - */ - @Test - @Ignore - public void getOrderPosition() { - - DB.ORDER_POSITION_1.getOrderId(); - Long orderPositionId = DB.ORDER_POSITION_1.getId(); - ResponseData position = - this.waiter.get(RestUrls.SalesManagement.Order.getGetOrderPositionURL(orderPositionId), OrderPositionEto.class); - assertThat(position.getResponseObject().getId(), is(orderPositionId)); - } - - /** - * Test update order position - */ - @Test - public void updateOrderPositionTest() { - - this.chief.post(RestUrls.SalesManagement.Order.getUpdateOrderPositionURL(), Additional.CHANGED_ORDER_POSITION_1); - - // ResponseData position = - // this.chief.get(RestUrls.SalesManagement.Order.getGetOrderPositionURL(1L, 1L), OrderPositionEto.class); - - // create table - TableEto table = TestData.createTable(null, 1L, null, TableState.FREE); - TableEto createdTable = this.chief.post(table, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - // create order - OrderCto order = TestData.createOrderCto(null, createdTable.getId(), null, OrderState.OPEN); - OrderCto createdOrder = this.waiter.post(order, RestUrls.SalesManagement.Order.getCreateOrderURL(), OrderCto.class); - // create order position - Money price = new Money(6.99); - OrderPositionEto orderPosition = - TestData.createOrderPosition(null, "Schnitzel-Menü", "mit Ketschup", OrderPositionState.DELIVERED, createdOrder - .getOrder().getId(), null, price); - OrderPositionEto createdOrderPosition = - this.waiter.post(orderPosition, RestUrls.SalesManagement.Order.getCreateOrderPositionURL(), - OrderPositionEto.class); - Money newPrice = price.add(new Money(1.01)); - createdOrderPosition.setPrice(newPrice); - // update order position - this.waiter.post(createdOrderPosition, RestUrls.SalesManagement.Order.getCreateOrderPositionURL(), - OrderPositionEto.class); - - ResponseData changedPosition = - this.chief.get(RestUrls.SalesManagement.Order.getGetOrderPositionURL(createdOrderPosition.getId()), - OrderPositionEto.class); - - assertThat(changedPosition.getResponseObject().getPrice(), is(newPrice)); - - } - - /** - * Tests the mark order position service - */ - @Test - @Ignore - public void markOrderPositionAsTest() { - - Long orderId = DB.ORDER_1.getId(); - Long orderPositionId = DB.ORDER_POSITION_1.getId(); - - this.chief.put(RestUrls.SalesManagement.Order.getMarkOrderPositionAsURL(orderId, orderPositionId, - OrderPositionState.CANCELLED), DB.ORDER_POSITION_1); - ResponseData position = - this.chief.get(RestUrls.SalesManagement.Order.getGetOrderPositionURL(orderPositionId), OrderPositionEto.class); - - assertThat(position.getResponseObject().getState(), is(OrderPositionState.CANCELLED)); - } - - /** - * Test change Table - */ - @Test - public void changeTableTest() { - - // create table - TableEto table = TestData.createTable(null, 1L, null, TableState.OCCUPIED); - TableEto createdTable = this.chief.post(table, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - TableEto tableTwo = TestData.createTable(null, 2L, null, TableState.FREE); - TableEto createdTableTwo = this.chief.post(tableTwo, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - TableEto tableThree = TestData.createTable(null, 3L, null, TableState.OCCUPIED); - TableEto createdTableThree = - this.chief.post(tableThree, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - // create order - OrderCto order = TestData.createOrderCto(null, createdTable.getId(), null, OrderState.OPEN); - OrderCto createdOrder = this.waiter.post(order, RestUrls.SalesManagement.Order.getCreateOrderURL(), OrderCto.class); - // change table - Response postStatusCode = - this.waiter.post(RestUrls.SalesManagement.Order.getChangeTableURL(createdOrder.getOrder().getId()), - createdTableTwo.getId()); - int CurrentPostStatus = postStatusCode.getStatus(); - assertThat(CurrentPostStatus, is(204)); - - ResponseData tableTwoStatus = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(createdTableTwo.getId()), TableEto.class); - assertThat(tableTwoStatus.getResponseObject().getState(), is(TableState.OCCUPIED)); - - ResponseData tableStatus = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(createdTable.getId()), TableEto.class); - assertThat(tableStatus.getResponseObject().getState(), is(TableState.FREE)); - - // Tests if you try to change the table to the current table - Response currentTableResp = - this.waiter.post(RestUrls.SalesManagement.Order.getChangeTableURL(createdOrder.getOrder().getId()), - createdOrder.getOrder().getTableId()); - int statusCodeCurrentTable = currentTableResp.getStatus(); - - assertThat(statusCodeCurrentTable, is(204)); - - // Tests if the exception gets thrown if you try to change the table to an occupied table - Response occupiedTableResp = - this.waiter.post(RestUrls.SalesManagement.Order.getChangeTableURL(createdOrder.getOrder().getId()), - createdTableThree.getId()); - - int statusCodeOccupiedTable = occupiedTableResp.getStatus(); - - assertThat(statusCodeOccupiedTable, is(400)); - - } - - /** - * Tests the get bill rest service - */ - @Test - @Ignore - public void getBill() { - - ResponseData bill = - this.waiter.get(RestUrls.SalesManagement.Bill.getGetBillURL(DB.BILL_1.getId()), BillEto.class); - assertThat(bill.getResponseObject().getId(), is(DB.BILL_1.getId())); - } - - /** - * Test the do payment rest service - */ - @Test - public void doPaymentTest() { - - // create table - TableEto table = TestData.createTable(null, 1L, null, TableState.FREE); - TableEto createdTable = this.chief.post(table, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - // create order - OrderCto order = TestData.createOrderCto(null, createdTable.getId(), null, OrderState.OPEN); - OrderCto createdOrder = this.waiter.post(order, RestUrls.SalesManagement.Order.getCreateOrderURL(), OrderCto.class); - // create order position - OrderPositionEto orderPosition = - TestData.createOrderPosition(null, "Schnitzel-Menü", "mit Ketschup", OrderPositionState.DELIVERED, createdOrder - .getOrder().getId(), null, new Money(BigDecimal.valueOf(6.99))); - OrderPositionEto createdOrderPosition = - this.waiter.post(orderPosition, RestUrls.SalesManagement.Order.getCreateOrderPositionURL(), - OrderPositionEto.class); - // create bill - BillEto bill = TestData.createBill(null, false, null, null, null, createdOrderPosition.getId()); - BillEto createdBill = - this.waiter.post(bill, RestUrls.SalesManagement.Bill.getCreateBillURL(new Money(BigDecimal.valueOf(6.99))), - BillEto.class); - this.waiter.post(RestUrls.SalesManagement.Bill.getDoPaymentURL(createdBill.getId())); - // get payed bill - ResponseData response = - this.waiter.get(RestUrls.SalesManagement.Bill.getGetBillURL(createdBill.getId()), BillCto.class); - // TODO: This check will not work currently because payment does not persist changes - // Please enable this when payment use case is completely implemented - // assertThat(response.getResponseObject().getBill().isPayed(), is(true)); - } - - /** - * Test the do payment rest service with payment data - */ - // @Test - public void doPaymentWithPaymentDataTest() { - - // This service is not supported yet as far as I can see - PaymentData paymentData = new CreditCardPaymentData(); - this.waiter.post(RestUrls.SalesManagement.Bill.getDoPaymentURL(DB.BILL_1.getId()), paymentData); - ResponseData bill = - this.waiter.get(RestUrls.SalesManagement.Bill.getGetBillURL(DB.BILL_1.getId()), BillEto.class); - assertThat(bill.getResponseObject().isPayed(), is(true)); - } - - /** - * Test the create bill service - */ - @Test - @Ignore - public void createBillTest() { - - Response r = - this.chief.post(RestUrls.SalesManagement.Bill.getCreateBillURL(new Money(10)), Additional.ORDER_POSITION); - assertThat(r.getStatus(), is(200)); - } - - /** - * Test the delteBill rest service - */ - @Test - public void deleteBillTest() { - - // create table - TableEto table = TestData.createTable(null, 1L, null, TableState.FREE); - TableEto createdTable = this.chief.post(table, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - // create order - OrderCto order = TestData.createOrderCto(null, createdTable.getId(), null, OrderState.OPEN); - OrderCto createdOrder = this.waiter.post(order, RestUrls.SalesManagement.Order.getCreateOrderURL(), OrderCto.class); - // create order position - OrderPositionEto orderPosition = - TestData.createOrderPosition(null, "Schnitzel-Menü", "mit Ketschup", OrderPositionState.DELIVERED, createdOrder - .getOrder().getId(), null, new Money(BigDecimal.valueOf(6.99))); - OrderPositionEto createdOrderPosition = - this.waiter.post(orderPosition, RestUrls.SalesManagement.Order.getCreateOrderPositionURL(), - OrderPositionEto.class); - // create bill - BillEto bill = TestData.createBill(null, false, null, null, null, createdOrderPosition.getId()); - BillEto createdBill = - this.waiter.post(bill, RestUrls.SalesManagement.Bill.getCreateBillURL(new Money(BigDecimal.valueOf(6.99))), - BillEto.class); - - this.chief.delete(RestUrls.SalesManagement.Bill.deleteBill(createdBill.getId())); - ResponseData response = - this.chief.get(RestUrls.SalesManagement.Bill.getGetBillURL(createdBill.getId()), BillCto.class); - assertThat(response.getResponseObject() == null, is(true)); - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/staffmanagement/services/StaffManagementRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/staffmanagement/services/StaffManagementRestServiceTest.java deleted file mode 100644 index fba3bbcbb..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/staffmanagement/services/StaffManagementRestServiceTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.oasp.gastronomy.restaurant.staffmanagement.services; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import io.oasp.gastronomy.restaurant.general.common.AbstractRestServiceTest; -import io.oasp.gastronomy.restaurant.staffmanagement.logic.api.to.StaffMemberEto; -import io.oasp.gastronomy.restaurant.test.config.RestUrls; -import io.oasp.gastronomy.restaurant.test.config.TestData.Additional; -import io.oasp.gastronomy.restaurant.test.config.TestData.DB; -import io.oasp.gastronomy.restaurant.test.general.webclient.ResponseData; - -import java.util.List; - -import org.junit.Ignore; -import org.junit.Test; - -/** - * Test staff management rest service - * - * @author arklos - */ -public class StaffManagementRestServiceTest extends AbstractRestServiceTest { - - /** - * Tests get staff member - */ - @Test - public void getStaffmemberTest() { - - ResponseData member = - this.waiter.get( - RestUrls.StaffManagement.getDeleteStaffMemberUrl(DB.STAFF_MEMEBR_1.getLastName().toLowerCase()), - StaffMemberEto.class); - assertThat(member.getResponse().getStatus(), is(200)); - assertThat(member.getResponseObject().getId(), is(DB.STAFF_MEMEBR_1.getId())); - } - - /** - * Test get all staff members - */ - @Test - public void getAllStaffmembersTest() { - - List> members = - this.waiter.getAll(RestUrls.StaffManagement.getGetAllStaffMembersUrl(), StaffMemberEto.class); - assertThat(4, is(members.size())); - } - - /** - * Tests update staffMember - */ - @Test - @Ignore - public void updateStaffMemberTest() { - - this.chief.put(RestUrls.StaffManagement.getUpdateStaffMember(DB.STAFF_MEMEBR_1.getLastName().toLowerCase()), - Additional.CHANGED_STAFF_MEMEBR_1); - ResponseData member = - this.chief.get(RestUrls.StaffManagement.getGetStaffMember(DB.STAFF_MEMEBR_1.getLastName().toLowerCase()), - StaffMemberEto.class); - assertThat(member.getResponse().getStatus(), is(200)); - assertThat(member.getResponseObject().getFirstName(), is(Additional.CHANGED_STAFF_MEMEBR_1.getFirstName())); - } - - /** - * Test delete member - */ - @Test - @Ignore - public void delteStaffMemberTest() { - - this.chief.delete(RestUrls.StaffManagement.getDeleteStaffMemberUrl(DB.STAFF_MEMEBR_1.getLastName().toLowerCase())); - List> members = - this.waiter.getAll(RestUrls.StaffManagement.getGetAllStaffMembersUrl(), StaffMemberEto.class); - assertThat(members.size(), is(DB.ALL_STAFF_MEMBER.size() - 1)); - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEntityBuilder.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEntityBuilder.java deleted file mode 100644 index 3187da3af..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEntityBuilder.java +++ /dev/null @@ -1,124 +0,0 @@ -package io.oasp.gastronomy.restaurant.tablemanagement.common.builders; - -import io.oasp.gastronomy.restaurant.general.common.P; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; -import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.TableEntity; - -import java.util.LinkedList; -import java.util.List; - -import javax.persistence.EntityManager; - -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallback; -import org.springframework.transaction.support.TransactionTemplate; - -import com.google.common.collect.Lists; - -public class TableEntityBuilder { - - private List> parameterToBeApplied; - - public TableEntityBuilder() { - - this.parameterToBeApplied = new LinkedList>(); - fillMandatoryFields(); - fillMandatoryFields_custom(); - } - - /** - * Might be enrichted to users needs (will not be overwritten) - */ - private void fillMandatoryFields_custom() { - - number(1l); - } - - /** - * Fills all mandatory fields by default. (will be overwritten on re-generation) - */ - private void fillMandatoryFields() { - - } - - public TableEntityBuilder number(final Long number) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEntity target) { - - target.setNumber(number); - } - }); - return this; - } - - public TableEntityBuilder waiterId(final Long waiterId) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEntity target) { - - target.setWaiterId(waiterId); - } - }); - return this; - } - - public TableEntityBuilder state(final TableState state) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEntity target) { - - target.setState(state); - } - }); - return this; - } - - public TableEntity createNew() { - - TableEntity tableentity = new TableEntity(); - for (P parameter : this.parameterToBeApplied) { - parameter.apply(tableentity); - } - return tableentity; - } - - public TableEntity persist(TransactionTemplate txt, final EntityManager em) { - - TableEntity tableentity = txt.execute(new TransactionCallback() { - - @Override - public TableEntity doInTransaction(TransactionStatus status) { - - TableEntity tableentity = createNew(); - em.persist(tableentity); - return tableentity; - } - }); - return tableentity; - } - - public List persistAndDuplicate(TransactionTemplate txt, final EntityManager em, final int quantity) { - - List tableentityList = txt.execute(new TransactionCallback>() { - - @Override - public List doInTransaction(TransactionStatus status) { - - List tableentityList = Lists.newLinkedList(); - for (int i = 0; i < quantity; i++) { - TableEntity tableentity = createNew(); - tableentity.setNumber(tableentity.getNumber() + i); - em.persist(tableentity); - tableentityList.add(tableentity); - } - return tableentityList; - } - }); - - return tableentityList; - } -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEtoBuilder.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEtoBuilder.java deleted file mode 100644 index 3930df13d..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/common/builders/TableEtoBuilder.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.oasp.gastronomy.restaurant.tablemanagement.common.builders; - -import io.oasp.gastronomy.restaurant.general.common.P; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; - -import java.util.LinkedList; -import java.util.List; - -public class TableEtoBuilder { - - private List> parameterToBeApplied; - - public TableEtoBuilder() { - - this.parameterToBeApplied = new LinkedList>(); - fillMandatoryFields(); - fillMandatoryFields_custom(); - } - - /** - * Might be enrichted to users needs (will not be overwritten) - */ - private void fillMandatoryFields_custom() { - - } - - /** - * Fills all mandatory fields by default. (will be overwritten on re-generation) - */ - private void fillMandatoryFields() { - - } - - public TableEtoBuilder waiterId(final Long waiterId) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEto target) { - - target.setWaiterId(waiterId); - } - }); - return this; - } - - public TableEtoBuilder number(final Long number) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEto target) { - - target.setNumber(number); - } - }); - return this; - } - - public TableEtoBuilder state(final TableState state) { - - this.parameterToBeApplied.add(new P() { - @Override - public void apply(TableEto target) { - - target.setState(state); - } - }); - return this; - } - - public TableEto createNew() { - - TableEto tableeto = new TableEto(); - for (P parameter : this.parameterToBeApplied) { - parameter.apply(tableeto); - } - return tableeto; - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/services/TableManagementRestServiceTest.java b/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/services/TableManagementRestServiceTest.java deleted file mode 100644 index a5195ab73..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/java/io/oasp/gastronomy/restaurant/tablemanagement/services/TableManagementRestServiceTest.java +++ /dev/null @@ -1,246 +0,0 @@ -package io.oasp.gastronomy.restaurant.tablemanagement.services; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import io.oasp.gastronomy.restaurant.general.common.AbstractRestServiceTest; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; -import io.oasp.gastronomy.restaurant.tablemanagement.common.builders.TableEntityBuilder; -import io.oasp.gastronomy.restaurant.tablemanagement.common.builders.TableEtoBuilder; -import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.TableEntity; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; -import io.oasp.gastronomy.restaurant.test.config.RestUrls; -import io.oasp.gastronomy.restaurant.test.config.TestData; -import io.oasp.gastronomy.restaurant.test.general.webclient.ResponseData; - -import java.util.ArrayList; -import java.util.List; - -import javax.ws.rs.core.Response; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - -/** - * Test table management rest service - * - * @author hahmad, arklos, mbrunnli - */ -public class TableManagementRestServiceTest extends AbstractRestServiceTest { - - /** - * Simple crud test for tablemanagement. - */ - @Test - public void crudTableTest() { - - // get all tables - List> tables = - this.waiter.getAll(RestUrls.TableManagement.getAllTablesUrl(), TableEto.class); - - // get unused table number - List tableNumbers = new ArrayList<>(); - for (ResponseData responseData : tables) { - tableNumbers.add(responseData.getResponseObject().getNumber()); - } - Long number = 1l; - while (tableNumbers.contains(number)) { - number += 1; - } - tableNumbers.add(number); - - // create a new table - TableEto createdTable = - this.waiter.post(TestData.createTable(null, number, 0, TableState.FREE), - RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - // get the created table - ResponseData table = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(createdTable.getId()), TableEto.class); - - Assert.assertNotNull(table.getResponseObject()); - Assert.assertEquals(createdTable.getNumber(), table.getResponseObject().getNumber()); - Assert.assertEquals(createdTable.getState(), table.getResponseObject().getState()); - - // update table - TableState newState = TableState.OCCUPIED; - createdTable.setState(newState); - Long newNumber = createdTable.getNumber() + 1l; - while (tableNumbers.contains(newNumber)) { - newNumber += 1; - } - createdTable.setNumber(newNumber); - TableEto updatedTable = - this.waiter.post(createdTable, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - - Assert.assertEquals(newState, updatedTable.getState()); - Assert.assertEquals(newNumber, updatedTable.getNumber()); - - // delete the table -- fails due to the OCCUPIED state - Response deleteResponse = this.chief.delete(RestUrls.TableManagement.getDeleteTableUrl(createdTable.getId())); - Assert.assertEquals(deleteResponse.getStatus(), 400); - - updatedTable = this.waiter.get(RestUrls.TableManagement.getGetTableUrl(createdTable.getId()), TableEto.class).getResponseObject(); - - newState = TableState.FREE; - updatedTable.setState(newState); - updatedTable = - this.waiter.post(updatedTable, RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - - Assert.assertEquals(newState, updatedTable.getState()); - - // delete the table table - deleteResponse = this.chief.delete(RestUrls.TableManagement.getDeleteTableUrl(createdTable.getId())); - Assert.assertEquals(deleteResponse.getStatus(), 204); - - // check if table is deleted - ResponseData getDeletedTableResponse = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(createdTable.getId()), TableEto.class); - Assert.assertNull(getDeletedTableResponse.getResponseObject()); - } - - /** - * Test get table - * - * @throws Exception test fails - */ - @Test - @Ignore - public void getTableTest() throws Exception { - - TableEntity tableEntity = - new TableEntityBuilder().number(10l).state(TableState.RESERVED) - .persist(this.transactionTemplate, TableManagementRestServiceTest.this.entityManager); - - ResponseData table = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(tableEntity.getId()), TableEto.class); - - Assert.assertNotNull(table.getResponseObject()); - Assert.assertEquals(tableEntity.getNumber(), table.getResponseObject().getNumber()); - Assert.assertEquals(tableEntity.getState(), table.getResponseObject().getState()); - - } - - /** - * Test get all tables - */ - @Test - public void getAllTablesTest() { - - List tableEntities = - new TableEntityBuilder().persistAndDuplicate(TableManagementRestServiceTest.this.transactionTemplate, - TableManagementRestServiceTest.this.entityManager, 5); - - List> tableEtos = - this.waiter.getAll(RestUrls.TableManagement.getAllTablesUrl(), TableEto.class); - - Assert.assertNotNull(tableEtos); - Assert.assertEquals(tableEntities.size(), tableEtos.size()); - } - - /** - * Test get all free tables - */ - @Test - public void getFreeTablesTest() { - - new TableEntityBuilder().state(TableState.OCCUPIED).persistAndDuplicate( - TableManagementRestServiceTest.this.transactionTemplate, TableManagementRestServiceTest.this.entityManager, 5); - new TableEntityBuilder() - .number(100l) - .state(TableState.FREE) - .persistAndDuplicate(TableManagementRestServiceTest.this.transactionTemplate, - TableManagementRestServiceTest.this.entityManager, 2); - new TableEntityBuilder() - .number(200l) - .state(TableState.RESERVED) - .persistAndDuplicate(TableManagementRestServiceTest.this.transactionTemplate, - TableManagementRestServiceTest.this.entityManager, 2); - - List> tableEtos = - this.waiter.getAll(RestUrls.TableManagement.getFreeTablesUrl(), TableEto.class); - - Assert.assertNotNull(tableEtos); - for (ResponseData responseData : tableEtos) { - Assert.assertNotNull(responseData.getResponseObject()); - Assert.assertEquals(TableState.FREE, responseData.getResponseObject().getState()); - } - } - - /** - * Test mark table as - */ - @Test - public void markTableAsTest() { - - TableEntity tableEntity = - new TableEntityBuilder().state(TableState.RESERVED).persist(this.transactionTemplate, this.entityManager); - - ResponseData table = - this.waiter.get(RestUrls.TableManagement.getGetTableUrl(tableEntity.getId()), TableEto.class); - table.getResponseObject().setState(TableState.OCCUPIED); - this.waiter.post(table.getResponseObject(), RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - - table = this.waiter.get(RestUrls.TableManagement.getGetTableUrl(tableEntity.getId()), TableEto.class); - assertThat(table.getResponse().getStatus(), is(200)); - assertThat(table.getResponseObject().getState(), is(TableState.OCCUPIED)); - - table.getResponseObject().setState(TableState.FREE); - this.waiter.post(table.getResponseObject(), RestUrls.TableManagement.getCreateTableUrl(), TableEto.class); - table = this.waiter.get(RestUrls.TableManagement.getGetTableUrl(tableEntity.getId()), TableEto.class); - assertThat(table.getResponse().getStatus(), is(200)); - assertThat(table.getResponseObject().getState(), is(TableState.FREE)); - } - - /** - * Test create table - */ - @Test - public void createTableTest() { - - this.chief.post(RestUrls.TableManagement.getCreateTableUrl(), - new TableEtoBuilder().number(10l).state(TableState.FREE).createNew()); - - List> tableEtos = - this.waiter.getAll(RestUrls.TableManagement.getAllTablesUrl(), TableEto.class); - - Assert.assertNotNull(tableEtos); - Assert.assertEquals(1, tableEtos.size()); - TableEto result = tableEtos.get(0).getResponseObject(); - Assert.assertNotNull(result); - Assert.assertEquals(new Long(10), result.getNumber()); - Assert.assertEquals(TableState.FREE, result.getState()); - } - - /** - * Test delete table - */ - @Test - public void deleteTableTest() { - - TableEntity tableToBeDeleted = - new TableEntityBuilder().state(TableState.FREE).persist(this.transactionTemplate, this.entityManager); - this.chief.delete(RestUrls.TableManagement.getDeleteTableUrl(tableToBeDeleted.getId())); - - List> tableEtos = - this.waiter.getAll(RestUrls.TableManagement.getAllTablesUrl(), TableEto.class); - - Assert.assertNotNull(tableEtos); - Assert.assertEquals(0, tableEtos.size()); - } - - /** - * Test is table releasable - */ - @Test - public void isTableReleaseable() { - - TableEntity tableTarget = - new TableEntityBuilder().state(TableState.OCCUPIED).persist(this.transactionTemplate, this.entityManager); - - ResponseData response = - this.waiter.get(RestUrls.TableManagement.isTableReleasableUrl(tableTarget.getId()), Boolean.class); - - assertThat(response.getResponseObject(), is(true)); - } - -} diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/app/dataaccess/beans-db-connector.xml b/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/app/dataaccess/beans-db-connector.xml deleted file mode 100644 index d6f9ab4c7..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/app/dataaccess/beans-db-connector.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/env/application.properties b/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/env/application.properties deleted file mode 100644 index a593353ed..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/env/application.properties +++ /dev/null @@ -1,24 +0,0 @@ -# ---------------------------------------------------------------------------- -# This file contains the environment specific properties of the application. -# It shall never be included in the deliverable of the application (WAR file). -# Therefore it is excluded during the build process with Maven. -# On the actual environment this file shall be provided with the according -# and correct settings in the following location of tomcat (CATALINA_HOME): -# lib/config/env/application.properties -# ---------------------------------------------------------------------------- - -# -database.hibernate.dialect = org.hibernate.dialect.H2Dialect -database.datasource = org.h2.jdbcx.JdbcDataSource -database.hibernate.hbm2ddl.auto = validate -#database.url = jdbc:h2:~/restaurant-db;INIT=create schema if not exists public -#database.url = jdbc:h2:tcp://localhost:${oasp.db.port}/restaurant-db;INIT=create schema if not exists public -database.url = jdbc:h2:tcp://localhost:${oasp.db.port}/.sample;INIT=create schema if not exists public -database.migration.auto = true -database.migration.testdata = true -database.migration.clean = true - -database.user.login = sa -database.user.password = - -#database.hibernate.show.sql = true diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/tomcat/tomcat-users.xml b/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/tomcat/tomcat-users.xml deleted file mode 100644 index 3b17d7ca3..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/config/tomcat/tomcat-users.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/initializeTests.sql b/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/initializeTests.sql deleted file mode 100644 index fbff88dfa..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/src/test/resources/initializeTests.sql +++ /dev/null @@ -1,16 +0,0 @@ -SET FOREIGN_KEY_CHECKS=0; - -DELETE FROM RestaurantTable; -DELETE FROM PRODUCT; -DELETE FROM OFFER; -DELETE FROM TABLEORDER; -DELETE FROM ORDERPOSITION; -DELETE FROM BILL; -DELETE FROM STAFFMEMBER; - -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (0, 'chief', 0, 'Charly', 'Chief', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (1, 'cook', 1, 'Carl', 'Cook', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (2, 'waiter', 2, 'Willy', 'Waiter', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (3, 'barkeeper', 3, 'Bianca', 'Barkeeper', 0); - -SET FOREIGN_KEY_CHECKS=1; \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server-integration/testdataexport.sql b/oasp4j-samples/oasp4j-sample-server-integration/testdataexport.sql deleted file mode 100644 index e2ec66aeb..000000000 --- a/oasp4j-samples/oasp4j-sample-server-integration/testdataexport.sql +++ /dev/null @@ -1,57 +0,0 @@ -SET REFERENTIAL_INTEGRITY FALSE; - -TRUNCATE TABLE STAFFMEMBER; -TRUNCATE TABLE BILL_ORDERPOSITION; -TRUNCATE TABLE OFFER; -TRUNCATE TABLE RestaurantTable; -TRUNCATE TABLE BILL; -TRUNCATE TABLE ORDERPOSITION; -TRUNCATE TABLE TABLEORDER; -TRUNCATE TABLE PRODUCT; - -SET REFERENTIAL_INTEGRITY TRUE; - -INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( 101 , 1 , 1 , 2 ); -INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( 102 , 2 , 1 , 0 ); -INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( 103 , 3 , 1 , 0 ); -INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( 104 , 4 , 1 , 0 ); -INSERT INTO RestaurantTable (id, number, modificationCounter, state) VALUES ( 105 , 5 , 1 , 0 ); - -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 1 , 'Meal' , 'Schnitzel' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 2 , 'Meal' , 'Goulasch' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 3 , 'Meal' , 'Pfifferlinge' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 4 , 'Meal' , 'Salat' , 1 ); - -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 5 , 'SideDish' , 'Pommes' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 6 , 'SideDish' , 'Reis' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 7 , 'SideDish' , 'Brot' , 1 ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter) VALUES ( 8 , 'SideDish' , 'Knödel' , 1 ); - -INSERT INTO PRODUCT (id, dtype, description, modificationCounter, alcoholic) VALUES ( 9 , 'Drink' , 'Wasser' , 1 , false ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter, alcoholic) VALUES ( 10 , 'Drink' , 'Cola' , 1 , false ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter, alcoholic) VALUES ( 11 , 'Drink' , 'Bier' , 1 , false ); -INSERT INTO PRODUCT (id, dtype, description, modificationCounter, alcoholic) VALUES ( 12 , 'Drink' , 'Wein / Apfelwein' , 1 , false ); - -INSERT INTO OFFER (id, description, state, meal_id, sidedish_id, drink_id, modificationCounter, currentprice) VALUES ( 1 , 'Schnitzel-Menü' , 0 , 1 , 5 , 10 , 1 , 6.99 ); -INSERT INTO OFFER (id, description, state, meal_id, sidedish_id, drink_id, modificationCounter, currentprice) VALUES ( 2 , 'Goulasch-Menü' , 0 , 2 , 6 , 11 , 1 , 7.99 ); -INSERT INTO OFFER (id, description, state, meal_id, sidedish_id, drink_id, modificationCounter, currentprice) VALUES ( 4 , 'Pfifferlinge-Menü' , 0 , 3 , 8 , 12 , 1 , 8.99 ); -INSERT INTO OFFER (id, description, state, meal_id, sidedish_id, drink_id, modificationCounter, currentprice) VALUES ( 5 , 'Salat-Menü' , 0 , 4 , 7 , 9 , 1 , 5.99 ); - -INSERT INTO TABLEORDER (id, tableid, modificationCounter, state) VALUES ( 1 , 1 , 1 , 1 ); - -INSERT INTO ORDERPOSITION (id, offername, comment, state, order_Id, modificationCounter, price) VALUES ( 1 , 'Schnitzel-Menü' , 'mit Ketschup' , 2 , 1 , 1 , 6.99 ); -INSERT INTO ORDERPOSITION (id, offername, comment, state, order_Id, modificationCounter, price) VALUES ( 2 , 'Goulasch-Menü' , '' , 2 , 1 , 1 , 7.99 ); -INSERT INTO ORDERPOSITION (id, offername, comment, state, order_Id, modificationCounter, price) VALUES ( 3 , 'Pfifferlinge-Menü' , '' , 2 , 1 , 1 , 8.99 ); -INSERT INTO ORDERPOSITION (id, offername, comment, state, order_Id, modificationCounter, price) VALUES ( 4 , 'Salat-Menü' , '' , 2 , 1 , 1 , 5.99 ); - -INSERT INTO BILL (id, payed, modificationCounter, totalamount,tip) VALUES ( 1 , false , 1 , 14.98 , 1.3 ); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES ( 1 , 1 ); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES ( 1 , 2 ); -INSERT INTO BILL (id, payed, modificationCounter, totalamount,tip) VALUES ( 2 , true , 1 , 14.98 , 1.4 ); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES ( 2 , 3 ); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES ( 2 , 4 ); - -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES ( 0 , 'chief' , 0 , 'Charly' , 'Chief' , 0 ); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES ( 1 , 'cook' , 1 , 'Carl' , 'Cook' , 0 ); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES ( 2 , 'waiter' , 2 , 'Willy' , 'Waiter' , 0 ); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES ( 3 , 'barkeeper' , 3 , 'Bianca' , 'Barkeeper' , 0 ); diff --git a/oasp4j-samples/oasp4j-sample-server/pom.xml b/oasp4j-samples/oasp4j-sample-server/pom.xml deleted file mode 100644 index 5f965dc1f..000000000 --- a/oasp4j-samples/oasp4j-sample-server/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-samples - dev-SNAPSHOT - - io.oasp.java.samples - oasp4j-sample-server - war - ${project.artifactId} - Server for the restaurant application - a simple example using the Open Application Standard Platform for Java (OASP4J). - - - - ${project.groupId} - oasp4j-sample-core - ${project.version} - - - - - - - jsclient - - false - - - - io.oasp.js - oasp4js-sample - 1.0.0-SNAPSHOT - zip - web - runtime - - - - - - org.apache.maven.plugins - maven-war-plugin - - - - io.oasp.js - oasp4js-sample - zip - web - jsclient - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-server/src/main/resources/logback.xml b/oasp4j-samples/oasp4j-sample-server/src/main/resources/logback.xml deleted file mode 100644 index 30d9e1b8e..000000000 --- a/oasp4j-samples/oasp4j-sample-server/src/main/resources/logback.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${filePath}${errorLogFile}.log - - WARN - - - ${filePath}${errorLogFile}_${rollingPattern}00.log - - - - ${logPattern} - - - - - - ${filePath}${infoLogFile}.log - - INFO - - - ${filePath}${infoLogFile}_${rollingPattern}00.log - - - - ${logPattern} - - - - - - ${filePath}${debugLogFile}.log - - ALL - - - ${filePath}${debugLogFile}_${rollingPattern}00.log - - - - ${logPattern} - - - - - - - - - ${logPattern} - - - DEBUG - - - - - - - - - - - - - - - - - - - diff --git a/oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/web.xml b/oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 99594cf7d..000000000 --- a/oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - Restaurant - - - - contextConfigLocation - classpath:config/app/beans-application.xml - - - - webAppRootKey - - oasp-sample-server - - - - - org.springframework.web.context.ContextLoaderListener - - - - - - - - Apache CXF Endpoint - cxf - cxf - org.apache.cxf.transport.servlet.CXFServlet - 1 - true - - - cxf - /services/* - - - - - mvc-dispatcher - org.springframework.web.servlet.DispatcherServlet - - contextConfigLocation - classpath:config/app/gui/dispatcher-servlet.xml - - 1 - true - - - mvc-dispatcher - /security/* - - - - - web-socket-dispatcher - org.springframework.web.servlet.DispatcherServlet - - contextConfigLocation - classpath:config/app/websocket/websocket-context.xml - - 1 - true - - - web-socket-dispatcher - /websocket/* - - - - DiagnosticContextFilter - io.oasp.module.logging.common.impl.DiagnosticContextFilter - true - - - DiagnosticContextFilter - /services/* - - - - - SecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - true - - - SecurityFilterChain - /* - - - - - SetCharacterEncodingFilter - org.springframework.web.filter.CharacterEncodingFilter - true - - encoding - UTF-8 - - - forceEncoding - true - - - - SetCharacterEncodingFilter - /* - - - - index.jsp - index.html - - - \ No newline at end of file diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/db/migration/V0001__Create_schema.sql b/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/db/migration/V0001__Create_schema.sql deleted file mode 100644 index ffc40bf71..000000000 --- a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/db/migration/V0001__Create_schema.sql +++ /dev/null @@ -1,11 +0,0 @@ --- TODO insert SQL statements to create the initial schema -CREATE SEQUENCE PUBLIC.HIBERNATE_SEQUENCE START WITH 1000000; - -CREATE TABLE PUBLIC.BINARYOBJECT ( - ID BIGINT NOT NULL, - MODIFICATIONCOUNTER INTEGER NOT NULL, - DATA BLOB(2147483647), - SIZE BIGINT NOT NULL, - MIMETYPE VARCHAR(255), - PRIMARY KEY (ID) -); \ No newline at end of file diff --git a/pom.xml b/pom.xml index c751f3e9c..65ff29314 100644 --- a/pom.xml +++ b/pom.xml @@ -12,20 +12,21 @@ 2014 - oasp4j-bom - oasp4j-modules - oasp4j-templates + bom + samples + templates 1.7 UTF-8 UTF-8 - 1.3.0 + 2.0.0 81 joerg.hohwiller@capgemini.com oss - 1.1.12.RELEASE + 1.3.0.RELEASE + src/main/client @@ -79,12 +80,37 @@ - + + + org.codehaus.mojo + flatten-maven-plugin + + ${oasp.flatten.mode} + + + + flatten + process-test-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + org.apache.maven.plugins maven-war-plugin - WEB-INF/lib/*-sources.jar + WEB-INF/classes/config/application.properties ${project.artifactId} @@ -151,6 +177,12 @@ maven-checkstyle-plugin 2.9.1 + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + org.apache.maven.plugins maven-project-info-reports-plugin @@ -187,6 +219,8 @@ maven-surefire-plugin 2.17 + + -Duser.language=en -Duser.region=EN ${basedir} @@ -242,7 +276,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.0.0-beta-4 + 1.0.0 org.eclipse.m2e @@ -383,37 +417,13 @@ - oasp4j-samples + samples deploy - - - org.codehaus.mojo - flatten-maven-plugin - - ${oasp.flatten.mode} - - - - flatten - process-test-resources - - flatten - - - - flatten.clean - clean - - clean - - - - org.apache.maven.plugins diff --git a/samples/batch/billExport.bat b/samples/batch/billExport.bat new file mode 100644 index 000000000..8ef1a419f --- /dev/null +++ b/samples/batch/billExport.bat @@ -0,0 +1,9 @@ +@echo off +call %~dp0\runbatch.bat billExportJob bills.file=%~dp0\tmp\bills.csv + +if errorlevel 0 goto success +echo Failed. +goto end +:success +echo Success. +:end \ No newline at end of file diff --git a/samples/batch/pom.xml b/samples/batch/pom.xml new file mode 100644 index 000000000..f915ea343 --- /dev/null +++ b/samples/batch/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + io.oasp.java.dev + oasp4j-samples + dev-SNAPSHOT + + io.oasp.java.samples + oasp4j-sample-batch + dev-SNAPSHOT + ${project.artifactId} + pom + Batches for the restaurant application - a simple example using the Open Application Standard Platform for Java (OASP4J). + + + ${project.groupId} + oasp4j-sample-core + ${project.version} + + + junit + junit + test + + + org.springframework + spring-test + test + + + + + + + maven-antrun-plugin + + + copy-config + package + + + + + + + run + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + + ${project.build.directory}/lib/ + + + + + + + + diff --git a/samples/batch/productImport.bat b/samples/batch/productImport.bat new file mode 100644 index 000000000..a9d8d2f44 --- /dev/null +++ b/samples/batch/productImport.bat @@ -0,0 +1,9 @@ +@echo off +call %~dp0\runbatch.bat productImportJob drinks.file=%~dp0\src\test\resources\drinks.csv meals.file=%~dp0\src\test\resources\meals.csv + +if errorlevel 0 goto success +echo Failed. +goto end +:success +echo Success. +:end \ No newline at end of file diff --git a/samples/batch/readme.txt b/samples/batch/readme.txt new file mode 100644 index 000000000..f123310c9 --- /dev/null +++ b/samples/batch/readme.txt @@ -0,0 +1,13 @@ +The purpose of this project is to build an executable jar with the sample application batches. +runbatch.bat is generic skript to run batches from command line +billExport.bat shows how to use this generic script to run the bill export. + +To actually run a batch build this project via + +mvn package + +and invoke the batch with + +billExport.bat + + diff --git a/samples/batch/runbatch.bat b/samples/batch/runbatch.bat new file mode 100644 index 000000000..726969eea --- /dev/null +++ b/samples/batch/runbatch.bat @@ -0,0 +1,2 @@ +rem This skript demonstrates how to run oasp batches via commandline +java -cp "%~dp0\target\lib\*;%~dp0\target\etc" -Doasp.db.port=8143 org.springframework.batch.core.launch.support.CommandLineJobRunner config/app/batch/beans-batch.xml %* \ No newline at end of file diff --git a/samples/batch/src/test/resources/drinks.csv b/samples/batch/src/test/resources/drinks.csv new file mode 100644 index 000000000..5870f32c7 --- /dev/null +++ b/samples/batch/src/test/resources/drinks.csv @@ -0,0 +1,3 @@ +Heineken, Pretty good beer, 1, true +Dilmah, Very tasty black tea, 2, false +Pepsi, Nice drink, 3, false diff --git a/samples/batch/src/test/resources/meals.csv b/samples/batch/src/test/resources/meals.csv new file mode 100644 index 000000000..914d8717a --- /dev/null +++ b/samples/batch/src/test/resources/meals.csv @@ -0,0 +1,4 @@ +Bratwurst, Tasty sausage, 1 +Hamburger, Big bun with meat, 2 +Tofu, Food made from soy milk, 3 +Pierogi, Very good filled dumplings, 4 diff --git a/oasp4j-samples/oasp4j-sample-core/pom.xml b/samples/core/pom.xml similarity index 74% rename from oasp4j-samples/oasp4j-sample-core/pom.xml rename to samples/core/pom.xml index 93e5c7334..436f6c930 100644 --- a/oasp4j-samples/oasp4j-sample-core/pom.xml +++ b/samples/core/pom.xml @@ -13,20 +13,24 @@ ${project.artifactId} Core of the server for the restaurant application - a simple example using the Open Application Standard Platform for Java (OASP4J). + + 1.7 + + io.oasp.java.modules - oasp4j-logging + oasp4j-batch io.oasp.java.modules - oasp4j-beanmapping + oasp4j-logging io.oasp.java.modules - oasp4j-configuration + oasp4j-beanmapping @@ -34,11 +38,17 @@ oasp4j-security + io.oasp.java.modules oasp4j-rest + + io.oasp.java.modules + oasp4j-basic + + io.oasp.java.modules oasp4j-jpa-envers @@ -86,15 +96,15 @@ @@ -173,11 +183,51 @@ + + org.springframework.batch + spring-batch-test + test + io.oasp.java.modules oasp4j-test test + + + javax.el + javax.el-api + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-security + + + + org.scala-lang + scala-library + 2.10.4 + + + org.springframework.boot + spring-boot-starter-ws + @@ -188,12 +238,27 @@ + + org.springframework.boot + spring-boot-maven-plugin + + io.oasp.gastronomy.restaurant.SpringBootApp + ZIP + + + + + repackage + + + + org.apache.maven.plugins maven-jar-plugin - config/env/* + config/application.properties diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/SpringBootApp.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/SpringBootApp.java new file mode 100644 index 000000000..cbd4f9b41 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/SpringBootApp.java @@ -0,0 +1,26 @@ +package io.oasp.gastronomy.restaurant; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.orm.jpa.EntityScan; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; + +import io.oasp.module.jpa.dataaccess.api.AdvancedRevisionEntity; + +//@SpringBootApplication(exclude = { SecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class }) +@SpringBootApplication(exclude = { EndpointAutoConfiguration.class }) +@EntityScan(basePackages = { "io.oasp.gastronomy.restaurant" }, basePackageClasses = { AdvancedRevisionEntity.class }) +@EnableGlobalMethodSecurity(jsr250Enabled = true) +public class SpringBootApp { + + /** + * Entry point for spring-boot based app + * + * @param args - arguments + */ + public static void main(String[] args) { + + SpringApplication.run(SpringBootApp.class, args); + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/ApplicationEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/ApplicationEntity.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/ApplicationEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/ApplicationEntity.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/BinaryObject.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/BinaryObject.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/BinaryObject.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/BinaryObject.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/MoneyHelper.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/MoneyHelper.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/MoneyHelper.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/MoneyHelper.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/NlsBundleApplicationRoot.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/NlsBundleApplicationRoot.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/NlsBundleApplicationRoot.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/NlsBundleApplicationRoot.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/UserProfile.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/UserProfile.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/UserProfile.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/UserProfile.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/Usermanagement.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/Usermanagement.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/Usermanagement.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/Usermanagement.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java similarity index 89% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java index 9f02a5d71..391b9fa03 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/NamedQueries.java @@ -26,5 +26,8 @@ public abstract class NamedQueries { /** @see io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.impl.dao.OrderDaoImpl */ public static final String GET_OPEN_ORDER_FOR_TABLE = "get.open.order.for.table"; + + /** @see io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.impl.dao.BillDaoImpl */ + public static final String GET_ALL_IDS_OF_PAYED_BILLS = "get.all.ids.of.payed.bills"; // END ARCHETYPE SKIP } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/PermissionConstants.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/PermissionConstants.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/PermissionConstants.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/constants/PermissionConstants.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java index 493da36b6..e827429d0 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Money.java @@ -13,7 +13,7 @@ * * @author hohwille */ -public class Money extends AbstractSimpleDatatype implements Comparable { +public class Money extends AbstractSimpleDatatype implements Comparable { /** A {@link Money} instance where the {@link #getValue() amount} is 0. */ public static final Money ZERO = new Money(BigDecimal.ZERO); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Role.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Role.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Role.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/Role.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoney.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoney.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoney.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoney.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java similarity index 93% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java index 8b572ba4e..27478377a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/datatype/validation/NotNegativeMoneyValidator.java @@ -1,12 +1,12 @@ package io.oasp.gastronomy.restaurant.general.common.api.datatype.validation; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; - import java.math.BigDecimal; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; + /** * Validates that an instance of Money must not have a negative price. * @@ -22,6 +22,9 @@ public void initialize(NotNegativeMoney constraintAnnotation) { @Override public boolean isValid(Money value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } return value.getValue().compareTo(BigDecimal.ZERO) >= 0; } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationBusinessException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationBusinessException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationBusinessException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationBusinessException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationTechnicalException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationTechnicalException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationTechnicalException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/ApplicationTechnicalException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalEntityStateException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalEntityStateException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalEntityStateException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalEntityStateException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalPropertyChangeException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalPropertyChangeException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalPropertyChangeException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/IllegalPropertyChangeException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/NoActiveUserException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/NoActiveUserException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/NoActiveUserException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/exception/NoActiveUserException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/security/UserData.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/security/UserData.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/security/UserData.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/security/UserData.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java index fbf4b3035..456b20a39 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/api/to/UserDetailsClientTo.java @@ -2,6 +2,7 @@ import io.oasp.gastronomy.restaurant.general.common.api.UserProfile; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Role; +import io.oasp.module.basic.common.api.to.AbstractTo; /** * This is the {@link AbstractTo TO} for the client view on the user details. diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/base/AbstractBeanMapperSupport.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/base/AbstractBeanMapperSupport.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/base/AbstractBeanMapperSupport.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/base/AbstractBeanMapperSupport.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java similarity index 81% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java index bb7599e2a..bde21b519 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/ApplicationAuthenticationProvider.java @@ -1,10 +1,5 @@ package io.oasp.gastronomy.restaurant.general.common.impl.security; -import io.oasp.gastronomy.restaurant.general.common.api.UserProfile; -import io.oasp.gastronomy.restaurant.general.common.api.Usermanagement; -import io.oasp.gastronomy.restaurant.general.common.api.security.UserData; -import io.oasp.module.security.common.base.accesscontrol.AbstractAccessControlBasedAuthenticationProvider; - import java.util.Set; import javax.inject.Inject; @@ -13,9 +8,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import io.oasp.gastronomy.restaurant.general.common.api.UserProfile; +import io.oasp.gastronomy.restaurant.general.common.api.Usermanagement; +import io.oasp.gastronomy.restaurant.general.common.api.security.UserData; +import io.oasp.module.security.common.base.accesscontrol.AbstractAccessControlBasedAuthenticationProvider; + /** * This class is responsible for the security aspects of authentication as well as providing user profile data and the * access-controls for authoriziation. @@ -25,8 +27,8 @@ * @author agreul */ @Named("ApplicationAuthenticationProvider") -public class ApplicationAuthenticationProvider extends - AbstractAccessControlBasedAuthenticationProvider { +public class ApplicationAuthenticationProvider + extends AbstractAccessControlBasedAuthenticationProvider { /** Logger instance. */ private static final Logger LOG = LoggerFactory.getLogger(ApplicationAuthenticationProvider.class); @@ -41,6 +43,13 @@ public ApplicationAuthenticationProvider() { super(); } + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + + authentication.setDetails(userDetails); + } + /** * @param usermanagement the {@link Usermanagement} to set */ diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/CsrfRequestMatcher.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/CsrfRequestMatcher.java new file mode 100644 index 000000000..ae91eb987 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/CsrfRequestMatcher.java @@ -0,0 +1,56 @@ +package io.oasp.gastronomy.restaurant.general.common.impl.security; + +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.security.web.util.matcher.RequestMatcher; + +/** + * This is the implementation of {@link RequestMatcher}, which decides which {@link HttpServletRequest Requests} require + * a correct CSRF token. + * + * @see Cross-site request forgery + * + * @author hohwille + */ +public class CsrfRequestMatcher implements RequestMatcher { + + private static final Pattern HTTP_METHOD_PATTERN = Pattern.compile("^GET$"); + + private static final String[] PATH_PREFIXES_WITHOUT_CSRF_PROTECTION = + { "/login", "/logout", "/services/rest/login", "/websocket" }; + + @Override + public boolean matches(HttpServletRequest request) { + + // GET requests are read-only and therefore do not need CSRF protection + if (HTTP_METHOD_PATTERN.matcher(request.getMethod()).matches()) { + + return false; + } + + // There are specific URLs which can not be protected from CSRF. For example, in case of the the login page, + // the CSRF token can only be accessed after a successful authentication ("login"). + String requestPath = getRequestPath(request); + for (String path : PATH_PREFIXES_WITHOUT_CSRF_PROTECTION) { + if (requestPath.startsWith(path)) { + return false; + } + } + + return true; + } + + private String getRequestPath(HttpServletRequest request) { + + String url = request.getServletPath(); + String pathInfo = request.getPathInfo(); + + if (pathInfo != null) { + url += pathInfo; + } + + return url; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java index 5cb5bc260..a46679695 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/common/impl/security/PrincipalAccessControlProviderImpl.java @@ -1,13 +1,13 @@ package io.oasp.gastronomy.restaurant.general.common.impl.security; -import io.oasp.gastronomy.restaurant.general.common.api.UserProfile; -import io.oasp.module.security.common.api.accesscontrol.PrincipalAccessControlProvider; - import java.util.Arrays; import java.util.Collection; import javax.inject.Named; +import io.oasp.gastronomy.restaurant.general.common.api.UserProfile; +import io.oasp.module.security.common.api.accesscontrol.PrincipalAccessControlProvider; + /** * The implementation of {@link PrincipalAccessControlProvider} for this sample application.
* ATTENTION:
diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansBatchConfig.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansBatchConfig.java new file mode 100644 index 000000000..41ed32cf5 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansBatchConfig.java @@ -0,0 +1,217 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +/** + * This class contains the configuration like jobLauncher,Jobrepository etc. + * @author ssarmoka + */ + +import javax.inject.Inject; +import javax.sql.DataSource; + +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.batch.core.configuration.support.MapJobRegistry; +import org.springframework.batch.core.explore.support.JobExplorerFactoryBean; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobOperator; +import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.transaction.PlatformTransactionManager; + +/** + * This class contains configuration of batch beans. + */ +@Configuration +public class BeansBatchConfig { + + /** + * JobRepository configuration + */ + private JobRepositoryFactoryBean jobRepository; + + /** + * JobRegistry configuration + */ + private MapJobRegistry jobRegistry; + + /** + * JobLauncher configuration + */ + private SimpleJobLauncher jobLauncher; + + /** + * JobExplorer configuration + */ + private JobExplorerFactoryBean jobExplorer; + + /** + * Datasource configuartion + */ + private DataSource dataSource; + + /** + * Transaction manager configuration + */ + private PlatformTransactionManager transactionManager; + + /** + * Isolation level configuration + */ + @Value("ISOLATION_DEFAULT") + private String isolationLevelForCreate; + + /** + * This method is creating joboperator bean + * + * @return SimpleJobOperator + */ + @Bean + @DependsOn({ "jobRepository", "jobExplorer", "jobRegistry", "jobLauncher" }) + public SimpleJobOperator jobOperator() { + + SimpleJobOperator jobOperator = new SimpleJobOperator(); + try { + jobOperator.setJobExplorer(this.jobExplorer.getObject()); + } catch (Exception e) { + throw new BeanCreationException("Could not create BatchJobOperator", e); + } + + jobOperator.setJobLauncher(this.jobLauncher); + jobOperator.setJobRegistry(this.jobRegistry); + + try { + jobOperator.setJobRepository(this.jobRepository.getObject()); + } catch (Exception e) { + throw new BeanCreationException("Could not create BatchJobOperator", e); + } + + return jobOperator; + } + + /** + * This method is creating jobrepository + * + * @return JobRepositoryFactoryBean + */ + @Bean(name = "jobRepository") + public JobRepositoryFactoryBean jobRepository() { + + this.jobRepository = new JobRepositoryFactoryBean(); + this.jobRepository.setDataSource(this.dataSource); + this.jobRepository.setTransactionManager(this.transactionManager); + this.jobRepository.setIsolationLevelForCreate(this.isolationLevelForCreate); + return this.jobRepository; + } + + /** + * This method is creating jobLauncher bean + * + * @return SimpleJobLauncher + */ + @Bean + @DependsOn("jobRepository") + public SimpleJobLauncher jobLauncher() { + + this.jobLauncher = new SimpleJobLauncher(); + + try { + this.jobLauncher.setJobRepository(this.jobRepository.getObject()); + } catch (Exception e) { + throw new BeanCreationException("Could not create BatchJobOperator", e); + } + + return this.jobLauncher; + } + + /** + * This method is creating jobExplorer bean + * + * @return JobExplorerFactoryBean + */ + @Bean + @DependsOn("dataSource") + public JobExplorerFactoryBean jobExplorer() { + + this.jobExplorer = new JobExplorerFactoryBean(); + this.jobExplorer.setDataSource(this.dataSource); + return this.jobExplorer; + } + + /** + * This method is creating jobRegistry bean + * + * @return MapJobRegistry + */ + @Bean + public MapJobRegistry jobRegistry() { + + this.jobRegistry = new MapJobRegistry(); + return this.jobRegistry; + } + + /** + * This method is creating JobRegistryBeanPostProcessor + * + * @return JobRegistryBeanPostProcessor + */ + @Bean + @DependsOn("jobRegistry") + public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() { + + JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor(); + postProcessor.setJobRegistry(this.jobRegistry); + return postProcessor; + } + + /** + * This method is creating incrementer + * + * @return RunIdIncrementer + */ + @Bean + public RunIdIncrementer incrementer() { + + return new RunIdIncrementer(); + } + + /** + * @return datasource + */ + public DataSource getDataSource() { + + return this.dataSource; + } + + /** + * @param datasource the datasource to set + */ + @Inject + public void setDataSource(DataSource datasource) { + + this.dataSource = datasource; + } + + /** + * + * @return transactionManager + */ + public PlatformTransactionManager getTransactionManager() { + + return this.transactionManager; + } + + /** + * + * @param transactionManager the transactionManager to set + */ + @Inject + public void setTransactionManager(PlatformTransactionManager transactionManager) { + + this.transactionManager = transactionManager; + } + +} diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansDozerConfiguration.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansDozerConfiguration.java new file mode 100644 index 000000000..9d5e70705 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/BeansDozerConfiguration.java @@ -0,0 +1,31 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import java.util.ArrayList; +import java.util.List; + +import org.dozer.DozerBeanMapper; +import org.dozer.Mapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * Java bean configuration for Dozer + * + * @author tkuzynow + */ +@Configuration +@ComponentScan(basePackages = { "io.oasp.module.beanmapping" }) +public class BeansDozerConfiguration { + + private static final String DOZER_MAPPING_XML = "config/app/common/dozer-mapping.xml"; + + @Bean + public Mapper getDozer() { + + List beanMappings = new ArrayList<>(); + beanMappings.add(DOZER_MAPPING_XML); + return new DozerBeanMapper(beanMappings); + + } +} diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/DefaultRolesPrefixPostProcessor.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/DefaultRolesPrefixPostProcessor.java new file mode 100644 index 000000000..951f840b7 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/DefaultRolesPrefixPostProcessor.java @@ -0,0 +1,61 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.PriorityOrdered; +import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; + +/** + * TODO hohwille This type ... + * + * @author hohwille + */ +public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered { + + private final String rolePrefix; + + /** + * Der Konstruktor. + * + * @param rolePrefix das gewünschte Rollen-Präfix (z.B. der leere String). + */ + public DefaultRolesPrefixPostProcessor(String rolePrefix) { + super(); + this.rolePrefix = rolePrefix; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + + // remove this if you are not using JSR-250 + if (bean instanceof Jsr250MethodSecurityMetadataSource) { + ((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(this.rolePrefix); + } + + if (bean instanceof DefaultMethodSecurityExpressionHandler) { + ((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(this.rolePrefix); + } + if (bean instanceof DefaultWebSecurityExpressionHandler) { + ((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(this.rolePrefix); + } + if (bean instanceof SecurityContextHolderAwareRequestFilter) { + ((SecurityContextHolderAwareRequestFilter) bean).setRolePrefix(this.rolePrefix); + } + return bean; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + + return bean; + } + + @Override + public int getOrder() { + + return PriorityOrdered.HIGHEST_PRECEDENCE; + } +} diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServiceConfiguration.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServiceConfiguration.java new file mode 100644 index 000000000..df3be66ef --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServiceConfiguration.java @@ -0,0 +1,127 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.inject.Inject; +import javax.ws.rs.Path; +import javax.ws.rs.ext.Provider; +import javax.xml.ws.Endpoint; + +import org.apache.cxf.bus.spring.SpringBus; +import org.apache.cxf.endpoint.Server; +import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; +import org.apache.cxf.jaxws.EndpointImpl; +import org.apache.cxf.transport.servlet.CXFServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.ws.config.annotation.EnableWs; +import org.springframework.ws.config.annotation.WsConfigurerAdapter; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +// BEGIN ARCHETYPE SKIP +import io.oasp.gastronomy.restaurant.tablemanagement.service.impl.ws.v1_0.TablemanagementWebServiceImpl; +// END ARCHETYPE SKIP +import io.oasp.module.rest.service.impl.RestServiceExceptionFacade; +import io.oasp.module.rest.service.impl.json.ObjectMapperFactory; + +@Configuration +@EnableWs +@ImportResource({ "classpath:META-INF/cxf/cxf.xml" /* , "classpath:META-INF/cxf/cxf-servlet.xml" */ }) +public class ServiceConfiguration extends WsConfigurerAdapter { + + /** Logger instance. */ + private static final Logger LOG = LoggerFactory.getLogger(ServiceConfiguration.class); + + public static final String URL_PATH_SERVICES = "/services"; + + public static final String URL_FOLDER_REST = "/rest"; + + public static final String URL_FOLDER_WEB_SERVICES = "/ws"; + + public static final String URL_PATH_REST_SERVICES = URL_PATH_SERVICES + URL_FOLDER_REST; + + public static final String URL_PATH_WEB_SERVICES = URL_PATH_SERVICES + URL_FOLDER_WEB_SERVICES; + + @Value("${security.expose.error.details}") + boolean exposeInternalErrorDetails; + + @Inject + private ApplicationContext applicationContext; + + @Inject + private ObjectMapperFactory objectMapperFactory; + + @Bean(name = "cxf") + public SpringBus springBus() { + + return new SpringBus(); + } + + @Bean + public JacksonJsonProvider jacksonJsonProvider() { + + return new JacksonJsonProvider(this.objectMapperFactory.createInstance()); + } + + @Bean + public ServletRegistrationBean servletRegistrationBean() { + + CXFServlet cxfServlet = new CXFServlet(); + ServletRegistrationBean servletRegistration = new ServletRegistrationBean(cxfServlet, URL_PATH_SERVICES + "/*"); + return servletRegistration; + } + + @Bean + public Server jaxRsServer() { + + // List restServiceBeans = new + // ArrayList<>(this.applicationContext.getBeansOfType(RestService.class).values()); + Collection restServices = findRestServices(); + if (restServices.isEmpty()) { + LOG.info("No REST Services have been found. Rest Endpoint will not be enabled in CXF."); + return null; + } + Collection providers = this.applicationContext.getBeansWithAnnotation(Provider.class).values(); + + JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean(); + factory.setBus(springBus()); + factory.setAddress(URL_FOLDER_REST); + // factory.set + factory.setServiceBeans(new ArrayList<>(restServices)); + factory.setProviders(new ArrayList<>(providers)); + + return factory.create(); + } + + private Collection findRestServices() { + + return this.applicationContext.getBeansWithAnnotation(Path.class).values(); + } + + @Bean + public RestServiceExceptionFacade restServiceExceptionFacade() { + + RestServiceExceptionFacade exceptionFacade = new RestServiceExceptionFacade(); + exceptionFacade.setExposeInternalErrorDetails(this.exposeInternalErrorDetails); + return exceptionFacade; + } + + // BEGIN ARCHETYPE SKIP + @Bean + public Endpoint tableManagement() { + + // Bus bus = (Bus) this.applicationContext.getBean(Bus.DEFAULT_BUS_ID); + EndpointImpl endpoint = new EndpointImpl(springBus(), new TablemanagementWebServiceImpl()); + endpoint.publish("/TablemanagementWebService"); + return endpoint; + } + // END ARCHETYPE SKIP +} \ No newline at end of file diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServletInitializer.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServletInitializer.java new file mode 100644 index 000000000..77852bfa5 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/ServletInitializer.java @@ -0,0 +1,23 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import io.oasp.gastronomy.restaurant.SpringBootApp; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.web.SpringBootServletInitializer; +import org.springframework.context.annotation.Configuration; + +/** + * This auto configuration will be used by spring boot to enable traditional deployment to a servlet container. You may + * remove this class if you run your application with embedded tomcat only. Tomcat startup will be twice as fast. + */ +@Configuration +@EnableAutoConfiguration +public class ServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + + return application.sources(SpringBootApp.class); + } +} diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebConfig.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebConfig.java new file mode 100644 index 000000000..9ba4e660a --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebConfig.java @@ -0,0 +1,87 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import io.oasp.module.logging.common.api.DiagnosticContextFacade; +import io.oasp.module.logging.common.impl.DiagnosticContextFacadeImpl; +import io.oasp.module.logging.common.impl.DiagnosticContextFilter; +import io.oasp.module.logging.common.impl.PerformanceLogFilter; + +import javax.servlet.Filter; + +import org.apache.catalina.filters.SetCharacterEncodingFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Registers a number of filters for web requests. + * + * @author rose + */ +@Configuration +public class WebConfig { + + private @Autowired AutowireCapableBeanFactory beanFactory; + + /** + * Register PerformanceLogFilter to log running time of requests. + * + * @return filter + */ + @Bean + public FilterRegistrationBean performanceLogFilter() { + + FilterRegistrationBean registration = new FilterRegistrationBean(); + Filter performanceLogFilter = new PerformanceLogFilter(); + this.beanFactory.autowireBean(performanceLogFilter); + registration.setFilter(performanceLogFilter); + registration.addUrlPatterns("/*"); + return registration; + } + + /** + * Bean definition for DiagnosticContextFacade. + * + * @return DiagnosticContextFacade + */ + @Bean(name = "DiagnosticContextFacade") + public DiagnosticContextFacade diagnosticContextFacade() { + + return new DiagnosticContextFacadeImpl(); + } + + /** + * Register DiagnosticContextFilter to log service calls with correlation id. + * + * @return filter + */ + @Bean + public FilterRegistrationBean diagnosticContextFilter() { + + FilterRegistrationBean registration = new FilterRegistrationBean(); + Filter diagnosticContextFilter = new DiagnosticContextFilter(); + this.beanFactory.autowireBean(diagnosticContextFilter); + registration.setFilter(diagnosticContextFilter); + registration.addUrlPatterns("/services/*"); + return registration; + } + + /** + * Register SetCharacterEncodingFilter to convert specical characters correctly. + * + * @return filter + */ + @Bean + public FilterRegistrationBean setCharacterEncodingFilter() { + + FilterRegistrationBean registration = new FilterRegistrationBean(); + SetCharacterEncodingFilter setCharacterEncodingFilter = new SetCharacterEncodingFilter(); + setCharacterEncodingFilter.setEncoding("UTF-8"); + setCharacterEncodingFilter.setIgnore(false); + this.beanFactory.autowireBean(setCharacterEncodingFilter); + registration.setFilter(setCharacterEncodingFilter); + registration.addUrlPatterns("/*"); + return registration; + } +} \ No newline at end of file diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebSecurityConfig.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebSecurityConfig.java new file mode 100644 index 000000000..ac6a4217c --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/configuration/WebSecurityConfig.java @@ -0,0 +1,193 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.servlet.Filter; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +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.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.security.web.authentication.logout.LogoutFilter; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CsrfFilter; +import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import io.oasp.gastronomy.restaurant.general.common.impl.security.ApplicationAuthenticationProvider; +import io.oasp.gastronomy.restaurant.general.common.impl.security.CsrfRequestMatcher; +import io.oasp.module.security.common.api.accesscontrol.AccessControlProvider; +import io.oasp.module.security.common.base.accesscontrol.AccessControlSchemaProvider; +import io.oasp.module.security.common.impl.accesscontrol.AccessControlProviderImpl; +import io.oasp.module.security.common.impl.accesscontrol.AccessControlSchemaProviderImpl; +import io.oasp.module.security.common.impl.rest.AuthenticationSuccessHandlerSendingOkHttpStatusCode; +import io.oasp.module.security.common.impl.rest.JsonUsernamePasswordAuthenticationFilter; +import io.oasp.module.security.common.impl.rest.LogoutSuccessHandlerReturningOkHttpStatusCode; + +/** + * Security configuration based on {@link WebSecurityConfigurerAdapter}. This configuration is by purpose designed most + * simple for two channels of authentication: simple login form and rest-url. + * + * @author hohwille, marcorose + */ +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Value("${security.cors.enabled}") + boolean corsEnabled=false; + + @Inject + private AuthenticationManagerBuilder authenticationManagerBuilder; + + @Inject + private ApplicationAuthenticationProvider authenticationProvider; + + @Bean + public AccessControlProvider accessControlProvider() { + + return new AccessControlProviderImpl(); + } + + @Bean + public AccessControlSchemaProvider accessControlSchemaProvider() { + + return new AccessControlSchemaProviderImpl(); + } + + @Bean + public CsrfTokenRepository csrfTokenRepository() { + + return new HttpSessionCsrfTokenRepository(); + } + + @Bean + public static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() { + + // By default Spring-Security is setting the prefix "ROLE_" for all permissions/authorities. + // We disable this undesired behavior here... + return new DefaultRolesPrefixPostProcessor(""); + } + + private CorsFilter getCorsFilter() { + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("OPTIONS"); + config.addAllowedMethod("HEAD"); + config.addAllowedMethod("GET"); + config.addAllowedMethod("PUT"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("DELETE"); + config.addAllowedMethod("PATCH"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + /** + * Configure spring security to enable a simple webform-login + a simple rest login. + */ + @Override + public void configure(HttpSecurity http) throws Exception { + + String[] unsecuredResources = + new String[] { "/login", "/security/**", "/services/rest/login", "/services/rest/logout" }; + + http + // + .authenticationProvider(this.authenticationProvider) + // define all urls that are not to be secured + .authorizeRequests().antMatchers(unsecuredResources).permitAll().anyRequest() + .authenticated() + .and() + + // activate crsf check for a selection of urls (but not for login & logout) + .csrf() + .requireCsrfProtectionMatcher(new CsrfRequestMatcher()) + .and() + + // configure parameters for simple form login (and logout) + .formLogin().successHandler(new SimpleUrlAuthenticationSuccessHandler()).defaultSuccessUrl("/") + .failureUrl("/login.html?error").loginProcessingUrl("/j_spring_security_login").usernameParameter("username") + .passwordParameter("password").and() + // logout via POST is possible + .logout().logoutSuccessUrl("/login.html").and() + + // register login and logout filter that handles rest logins + .addFilterAfter(getSimpleRestAuthenticationFilter(), BasicAuthenticationFilter.class) + .addFilterAfter(getSimpleRestLogoutFilter(), LogoutFilter.class); + + if (corsEnabled){ + http.addFilterBefore(getCorsFilter(),CsrfFilter.class); + } + } + + /** + * Create a simple filter that allows logout on a REST Url /services/rest/logout and returns a simple HTTP status 200 + * ok. + * + * @return the filter. + */ + private Filter getSimpleRestLogoutFilter() { + + LogoutFilter logoutFilter = + new LogoutFilter(new LogoutSuccessHandlerReturningOkHttpStatusCode(), new SecurityContextLogoutHandler()); + + // configure logout for rest logouts + logoutFilter.setLogoutRequestMatcher(new AntPathRequestMatcher("/services/rest/logout")); + + return logoutFilter; + } + + /** + * Create a simple authentication filter for REST logins that reads user-credentials from a json-parameter and returns + * status 200 instead of redirect after login. + * + * @return the AuthenticationFilter + * @throws Exception + */ + protected JsonUsernamePasswordAuthenticationFilter getSimpleRestAuthenticationFilter() throws Exception { + + JsonUsernamePasswordAuthenticationFilter jsonFilter = + new JsonUsernamePasswordAuthenticationFilter(new AntPathRequestMatcher("/services/rest/login")); + jsonFilter.setPasswordParameter("j_password"); + jsonFilter.setUsernameParameter("j_username"); + jsonFilter.setAuthenticationManager(authenticationManager()); + // set failurehandler that uses no redirect in case of login failure; just HTTP-status: 401 + jsonFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler()); + // set successhandler that uses no redirect in case of login success; just HTTP-status: 200 + jsonFilter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandlerSendingOkHttpStatusCode()); + return jsonFilter; + } + + /** + * Init the authenticationManager and simply set users and roles here (to keep things as simplistic as possible). + * + * @throws Exception + */ + @PostConstruct + public void init() throws Exception { + + this.authenticationManagerBuilder.inMemoryAuthentication() // + .withUser("waiter").password("waiter").roles("Waiter").and() // + .withUser("cook").password("cook").roles("Cook").and() // + .withUser("barkeeper").password("barkeeper").roles("Barkeeeper") // + .and().withUser("chief").password("chief").roles("Chief"); + + // add our own authenticatonProvider that has add on functionality compared to spring security + this.authenticationManagerBuilder.authenticationProvider(this.authenticationProvider); + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/ApplicationPersistenceEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/ApplicationPersistenceEntity.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/ApplicationPersistenceEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/ApplicationPersistenceEntity.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java index ee49b2f86..e2bebffe9 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/BinaryObjectEntity.java @@ -6,13 +6,15 @@ import javax.persistence.Entity; import javax.persistence.Lob; +import javax.persistence.Table; /** * {@link ApplicationPersistenceEntity Entity} for {@link BinaryObject}. Contains the actual {@link Blob}. * * @author sspielma */ -@Entity(name = "BinaryObject") +@Entity +@Table(name = "BinaryObject") public class BinaryObjectEntity extends ApplicationPersistenceEntity implements BinaryObject { private static final long serialVersionUID = 1L; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationRevisionedDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationRevisionedDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationRevisionedDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/ApplicationRevisionedDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/BinaryObjectDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/BinaryObjectDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/BinaryObjectDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/api/dao/BinaryObjectDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java similarity index 86% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java index f6857c407..95aa103a3 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/DatabaseMigrator.java @@ -49,6 +49,19 @@ public void migrate() { } } + /** + * Import test data. + * + * @param importTestDataPath path to directory with files with test data + */ + public void importTestData(String importTestDataPath) { + + final Flyway flyway = new Flyway(); + flyway.setDataSource(this.dataSource); + flyway.setLocations(importTestDataPath); + flyway.migrate(); + } + /** * @return enabled */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/MoneyAttributeConverter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/MoneyAttributeConverter.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/MoneyAttributeConverter.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/MoneyAttributeConverter.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationMasterDataDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationMasterDataDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationMasterDataDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/ApplicationMasterDataDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/BinaryObjectDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/BinaryObjectDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/BinaryObjectDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/dataaccess/base/dao/BinaryObjectDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java similarity index 97% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java index 1638facb8..d28c7b074 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/gui/api/LoginController.java @@ -19,7 +19,7 @@ public class LoginController { /** * Default URL to redirect to after successfully login. */ - public final static String defaultTargetUrl = "/services"; + public final static String defaultTargetUrl = "/"; /** * Builds the model for the login page---mainly focusing on the error message handling. diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/UseCase.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/UseCase.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/UseCase.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/UseCase.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java similarity index 80% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java index efe20ebdc..97820108a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/api/to/BinaryObjectEto.java @@ -1,10 +1,10 @@ package io.oasp.gastronomy.restaurant.general.logic.api.to; import io.oasp.gastronomy.restaurant.general.common.api.BinaryObject; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; +import io.oasp.module.basic.common.api.to.AbstractEto; /** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for a {@link BinaryObject}. + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for a {@link BinaryObject}. * * @author sspielma */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java similarity index 99% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java index f27eb7a61..fd171f9d2 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractComponentFacade.java @@ -1,6 +1,5 @@ package io.oasp.gastronomy.restaurant.general.logic.base; - import io.oasp.gastronomy.restaurant.general.common.base.AbstractBeanMapperSupport; import io.oasp.module.jpa.common.api.to.PaginatedListTo; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractUc.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractUc.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractUc.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/AbstractUc.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/UcManageBinaryObject.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/UcManageBinaryObject.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/UcManageBinaryObject.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/base/UcManageBinaryObject.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java index 498c7422f..35a8c7cab 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/logic/impl/UcManageBinaryObjectImpl.java @@ -2,7 +2,6 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.BinaryObjectEntity; import io.oasp.gastronomy.restaurant.general.dataaccess.api.dao.BinaryObjectDao; -import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; import io.oasp.gastronomy.restaurant.general.logic.base.AbstractUc; import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; @@ -18,7 +17,6 @@ * @author sspielma */ @Named -@UseCase public class UcManageBinaryObjectImpl extends AbstractUc implements UcManageBinaryObject { /** @see #binaryObjectDao */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationAccessDeniedHandler.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationAccessDeniedHandler.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationAccessDeniedHandler.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationAccessDeniedHandler.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationObjectMapperFactory.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationObjectMapperFactory.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationObjectMapperFactory.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/ApplicationObjectMapperFactory.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonDeserializer.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonDeserializer.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonDeserializer.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonDeserializer.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonSerializer.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonSerializer.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonSerializer.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/MoneyJsonSerializer.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/SecurityRestServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/SecurityRestServiceImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/SecurityRestServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/general/service/impl/rest/SecurityRestServiceImpl.java diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/writer/ProductWriter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/writer/ProductWriter.java new file mode 100644 index 000000000..62fba5be7 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/writer/ProductWriter.java @@ -0,0 +1,48 @@ +package io.oasp.gastronomy.restaurant.offermanagement.batch.impl.productimport.writer; + +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; + +import java.util.List; + +import javax.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.item.ItemWriter; + +/** + * ProductWriter is responsible for writing ProductEto to database. + * + * @author abielewi + */ +public class ProductWriter implements ItemWriter { + + private static final Logger LOG = LoggerFactory.getLogger(ProductWriter.class); + + private Offermanagement offerManagement; + + /** + * {@inheritDoc} + */ + @Override + public void write(List items) throws Exception { + + LOG.debug("Writing " + items.size() + " products"); + + for (ProductEto item : items) { + LOG.debug("Saving product: " + item.getName()); + this.offerManagement.saveProduct(item); + } + + } + + /** + * @param offerManagement the offerManagement to set + */ + @Inject + public void setOfferManagement(Offermanagement offerManagement) { + + this.offerManagement = offerManagement; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Drink.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Drink.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Drink.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Drink.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Meal.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Meal.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Meal.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Meal.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/MenuItem.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/MenuItem.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/MenuItem.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/MenuItem.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java index 189390ece..72fda53cf 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Offer.java @@ -35,8 +35,8 @@ public interface Offer extends MenuItem { void setPrice(Money price); /** - * @return is the {@link Meal#getId() ID} of the {@link Meal} or {@code null} if no {@link Meal} is contained in this - * {@link Offer}. + * @return is the {@link Meal#getId() ID} of the {@link Meal} or {@code null} if no {@link Meal} is contained in + * this {@link Offer}. */ Long getMealId(); @@ -46,8 +46,8 @@ public interface Offer extends MenuItem { void setMealId(Long mealId); /** - * @return is the {@link Drink#getId() ID} of the {@link Drink} or {@code null} if no {@link Drink} is contained in - * this {@link Offer}. + * @return is the {@link Drink#getId() ID} of the {@link Drink} or {@code null} if no {@link Drink} is contained + * in this {@link Offer}. */ Long getDrinkId(); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Product.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Product.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Product.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/Product.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/SideDish.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/SideDish.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/SideDish.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/SideDish.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/DayOfWeek.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferSortByHitEntry.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferSortByHitEntry.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferSortByHitEntry.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferSortByHitEntry.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferState.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferState.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferState.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/OfferState.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductSortByHitEntry.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductSortByHitEntry.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductSortByHitEntry.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductSortByHitEntry.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductType.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductType.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductType.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/datatype/ProductType.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/exception/OfferEmptyException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/exception/OfferEmptyException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/exception/OfferEmptyException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/common/api/exception/OfferEmptyException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java index 5533324dc..d6feda39e 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/DrinkEntity.java @@ -13,7 +13,7 @@ * * @author loverbec */ -@Entity(name = "Drink") +@Entity @DiscriminatorValue("Drink") @Audited public class DrinkEntity extends ProductEntity implements Drink { @@ -35,6 +35,7 @@ public DrinkEntity() { * * @return Value of alcoholic */ + @Override public boolean isAlcoholic() { return this.alcoholic; @@ -45,6 +46,7 @@ public boolean isAlcoholic() { * * @param alcoholic New value for alcoholic */ + @Override public void setAlcoholic(boolean alcoholic) { this.alcoholic = alcoholic; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java index 4fc57374a..f1a28e7e2 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MealEntity.java @@ -13,7 +13,7 @@ * * @author loverbec */ -@Entity(name = "Meal") +@Entity @DiscriminatorValue("Meal") @Audited public class MealEntity extends ProductEntity implements Meal { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MenuItemEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MenuItemEntity.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MenuItemEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/MenuItemEntity.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java similarity index 97% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java index ed3b77951..38ebb6505 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/OfferEntity.java @@ -18,8 +18,8 @@ * * @author loverbec */ -@Entity(name = "Offer") -@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "description" }) }) +@Entity +@Table(name = "Offer", uniqueConstraints = { @UniqueConstraint(columnNames = { "description" }) }) public class OfferEntity extends MenuItemEntity implements Offer { private static final long serialVersionUID = 1L; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java index 686653707..45e45e680 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/ProductEntity.java @@ -7,6 +7,7 @@ import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; +import javax.persistence.Table; import org.hibernate.envers.Audited; @@ -16,7 +17,8 @@ * * @author loverbec */ -@Entity(name = "Product") +@Entity +@Table(name = "Product") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING) @Audited diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java index 041cbba76..3402093d9 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SideDishEntity.java @@ -13,7 +13,7 @@ * * @author loverbec */ -@Entity(name = "SideDish") +@Entity @DiscriminatorValue("SideDish") @Audited public class SideDishEntity extends ProductEntity implements SideDish { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java index ddcda9374..a5a75627a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/SpecialEntity.java @@ -1,111 +1,111 @@ -package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; - -import javax.persistence.Column; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Table; - -/** - * The {@link ApplicationPersistenceEntity persistent entity} for a special. - * - * @author mbrunnli - */ -@Entity(name = "Special") -@Table(name = "Special") -public class SpecialEntity { - - private String name; - - private OfferEntity offer; - - @Embedded - private WeeklyPeriodEmbeddable activePeriod; - - private Money specialPrice; - - /** - * Returns the name of this special. - * - * @return name the name of this special. - */ - @Column(unique = true) - public String getName() { - - return this.name; - } - - /** - * Sets the name of this special. - * - * @param name the name of this special. - */ - public void setName(String name) { - - this.name = name; - } - - /** - * Returns the {@link Offer} this special applies for. - * - * @return offer {@link Offer} this special applies for. - */ - public OfferEntity getOffer() { - - return this.offer; - } - - /** - * Sets the {@link Offer} this special applies for. - * - * @param offer the {@link Offer} this special applies for. - */ - public void setOffer(OfferEntity offer) { - - this.offer = offer; - } - - /** - * Returns the {@link WeeklyPeriodEmbeddable active period} this special applies for. - * - * @return activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. - */ - public WeeklyPeriodEmbeddable getActivePeriod() { - - return this.activePeriod; - } - - /** - * Sets the {@link WeeklyPeriodEmbeddable active period} this special applies for. - * - * @param activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. - */ - public void setActivePeriod(WeeklyPeriodEmbeddable activePeriod) { - - this.activePeriod = activePeriod; - } - - /** - * Returns the new {@link Money special price} for the {@link Offer}. - * - * @return specialPrice the new {@link Money special price} for the {@link Offer}. - */ - public Money getSpecialPrice() { - - return this.specialPrice; - } - - /** - * Sets the new {@link Money special price} for the {@link Offer}. - * - * @param specialPrice the new {@link Money special price} for the {@link Offer}. - */ - public void setSpecialPrice(Money specialPrice) { - - this.specialPrice = specialPrice; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; + +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * The {@link ApplicationPersistenceEntity persistent entity} for a special. + * + * @author mbrunnli + */ +@Entity(name = "Special") +@Table(name = "Special") +public class SpecialEntity { + + private String name; + + private OfferEntity offer; + + @Embedded + private WeeklyPeriodEmbeddable activePeriod; + + private Money specialPrice; + + /** + * Returns the name of this special. + * + * @return name the name of this special. + */ + @Column(unique = true) + public String getName() { + + return this.name; + } + + /** + * Sets the name of this special. + * + * @param name the name of this special. + */ + public void setName(String name) { + + this.name = name; + } + + /** + * Returns the {@link Offer} this special applies for. + * + * @return offer {@link Offer} this special applies for. + */ + public OfferEntity getOffer() { + + return this.offer; + } + + /** + * Sets the {@link Offer} this special applies for. + * + * @param offer the {@link Offer} this special applies for. + */ + public void setOffer(OfferEntity offer) { + + this.offer = offer; + } + + /** + * Returns the {@link WeeklyPeriodEmbeddable active period} this special applies for. + * + * @return activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. + */ + public WeeklyPeriodEmbeddable getActivePeriod() { + + return this.activePeriod; + } + + /** + * Sets the {@link WeeklyPeriodEmbeddable active period} this special applies for. + * + * @param activePeriod the {@link WeeklyPeriodEmbeddable active period} this special applies for. + */ + public void setActivePeriod(WeeklyPeriodEmbeddable activePeriod) { + + this.activePeriod = activePeriod; + } + + /** + * Returns the new {@link Money special price} for the {@link Offer}. + * + * @return specialPrice the new {@link Money special price} for the {@link Offer}. + */ + public Money getSpecialPrice() { + + return this.specialPrice; + } + + /** + * Sets the new {@link Money special price} for the {@link Offer}. + * + * @param specialPrice the new {@link Money special price} for the {@link Offer}. + */ + public void setSpecialPrice(Money specialPrice) { + + this.specialPrice = specialPrice; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java index 857ff8254..5c80c1406 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/WeeklyPeriodEmbeddable.java @@ -1,110 +1,110 @@ -package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; - -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.DayOfWeek; - -import javax.persistence.Embeddable; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; - -/** - * Weekly period describing a starting and an ending point. Each is defined as a fixed hour (24h-format) at a specific - * day of week. - * - * @author mbrunnli - */ -@Embeddable -public class WeeklyPeriodEmbeddable { - - private DayOfWeek startingDay; - - private int startingHour; - - private DayOfWeek endingDay; - - private int endingHour; - - /** - * Returns the {@link DayOfWeek} the period starts. - * - * @return startingDay the {@link DayOfWeek} the period starts. - */ - public DayOfWeek getStartingDay() { - - return this.startingDay; - } - - /** - * Sets the {@link DayOfWeek} the period starts. - * - * @param startingDay the {@link DayOfWeek} the period starts. - */ - public void setStartingDay(DayOfWeek startingDay) { - - this.startingDay = startingDay; - } - - /** - * Returns the hour (in 24h-format) the period starts. - * - * @return startingHour the hour (in 24h-format) the period starts. - */ - @Max(24) - @Min(0) - public int getStartingHour() { - - return this.startingHour; - } - - /** - * Sets the hour (in 24h-format) the period starts. - * - * @param startingHour the hour (in 24h-format) the period starts. - */ - public void setStartingHour(int startingHour) { - - this.startingHour = startingHour; - } - - /** - * Returns the {@link DayOfWeek} the period ends. - * - * @return endingDay the {@link DayOfWeek} the period ends. - */ - public DayOfWeek getEndingDay() { - - return this.endingDay; - } - - /** - * Sets the {@link DayOfWeek} the period ends. - * - * @param endingDay the {@link DayOfWeek} the period ends. - */ - public void setEndingDay(DayOfWeek endingDay) { - - this.endingDay = endingDay; - } - - /** - * Returns the hour (in 24h-format) the period ends. - * - * @return endingHour the hour (in 24h-format) the period ends. - */ - @Max(24) - @Min(0) - public int getEndingHour() { - - return this.endingHour; - } - - /** - * Returns the hour (in 24h-format) the period ends. - * - * @param endingHour the hour (in 24h-format) the period ends. - */ - public void setEndingHour(int endingHour) { - - this.endingHour = endingHour; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.DayOfWeek; + +import javax.persistence.Embeddable; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +/** + * Weekly period describing a starting and an ending point. Each is defined as a fixed hour (24h-format) at a specific + * day of week. + * + * @author mbrunnli + */ +@Embeddable +public class WeeklyPeriodEmbeddable { + + private DayOfWeek startingDay; + + private int startingHour; + + private DayOfWeek endingDay; + + private int endingHour; + + /** + * Returns the {@link DayOfWeek} the period starts. + * + * @return startingDay the {@link DayOfWeek} the period starts. + */ + public DayOfWeek getStartingDay() { + + return this.startingDay; + } + + /** + * Sets the {@link DayOfWeek} the period starts. + * + * @param startingDay the {@link DayOfWeek} the period starts. + */ + public void setStartingDay(DayOfWeek startingDay) { + + this.startingDay = startingDay; + } + + /** + * Returns the hour (in 24h-format) the period starts. + * + * @return startingHour the hour (in 24h-format) the period starts. + */ + @Max(24) + @Min(0) + public int getStartingHour() { + + return this.startingHour; + } + + /** + * Sets the hour (in 24h-format) the period starts. + * + * @param startingHour the hour (in 24h-format) the period starts. + */ + public void setStartingHour(int startingHour) { + + this.startingHour = startingHour; + } + + /** + * Returns the {@link DayOfWeek} the period ends. + * + * @return endingDay the {@link DayOfWeek} the period ends. + */ + public DayOfWeek getEndingDay() { + + return this.endingDay; + } + + /** + * Sets the {@link DayOfWeek} the period ends. + * + * @param endingDay the {@link DayOfWeek} the period ends. + */ + public void setEndingDay(DayOfWeek endingDay) { + + this.endingDay = endingDay; + } + + /** + * Returns the hour (in 24h-format) the period ends. + * + * @return endingHour the hour (in 24h-format) the period ends. + */ + @Max(24) + @Min(0) + public int getEndingHour() { + + return this.endingHour; + } + + /** + * Returns the hour (in 24h-format) the period ends. + * + * @param endingHour the hour (in 24h-format) the period ends. + */ + public void setEndingHour(int endingHour) { + + this.endingHour = endingHour; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/DrinkDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/DrinkDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/DrinkDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/DrinkDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/MealDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/MealDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/MealDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/MealDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/OfferDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/OfferDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/OfferDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/OfferDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/ProductDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/ProductDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/ProductDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/ProductDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/SideDishDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/SideDishDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/SideDishDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/api/dao/SideDishDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/DrinkDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/DrinkDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/DrinkDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/DrinkDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/MealDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/MealDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/MealDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/MealDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java similarity index 99% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java index e8a8c4c3d..0d7509e0f 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/ProductDaoImpl.java @@ -171,8 +171,6 @@ public PaginatedListTo findProducts(ProductSearchCriteriaTo crite query.where(Alias.$(product.getDescription()).eq(description)); } - System.out.println("criteria: " + criteria.toStrink()); - // include filter for entity type if (!(criteria.isFetchDrinks() || criteria.isFetchMeals() || criteria.isFetchSideDishes())) { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/SideDishDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/SideDishDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/SideDishDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/SideDishDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java similarity index 54% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java index df9973ba2..2b3fcea97 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/usecase/UcFindProduct.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/Offermanagement.java @@ -1,8 +1,13 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase; +package io.oasp.gastronomy.restaurant.offermanagement.logic.api; import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; @@ -13,13 +18,78 @@ import java.sql.Blob; import java.util.List; +import javax.validation.Valid; + /** - * Interface of UcFindProduct to centralize documentation and signatures of methods. + * Interface for OfferManagement. * - * @author mbrunnli - * @since dev + * @author loverbec */ -public interface UcFindProduct { +public interface Offermanagement { + + /** + * Gets an {@link OfferEto} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. + */ + OfferEto findOffer(Long id); + + /** + * Gets an {@link OfferCto} using its entity identifier. + * + * @param id is the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer#getId() offer ID}. + * @return the requested {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} or {@code null} if no + * such {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} exists. + */ + OfferCto findOfferCto(Long id); + + /** + * @return the {@link List} with all available {@link OfferEto}s. + */ + List findAllOffers(); + + /** + * Returns a list of offers matching the search criteria. + * + * @param criteria the {@link OfferSearchCriteriaTo}. + * @return the {@link List} of matching {@link OfferEto}s. + */ + PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria); + + /** + * Checks, whether a given {@link ProductEto} is in use by at least one {@link OfferEto}. + * + * @param product product to check if it is in use + * @return {@code true}, if there are no {@link OfferEto offers}, that use the given {@link ProductEto}. {@code false} + * otherwise. + */ + boolean isProductInUseByOffer(ProductEto product); + + /** + * @param offerFilterBo is the {@link OfferFilter offers filter criteria} + * @param sortBy is the {@link OfferSortBy} attribute, which defines the sorting. + * + * @return the {@link List} with all {@link OfferEto}s that match the {@link OfferFilter} criteria. + */ + List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy); + + /** + * Deletes an {@link OfferEto} by its {@link OfferEto#getId() id}. + * + * @param offerId is the {@link OfferEto#getId() id} that identifies the {@link OfferEto} to be deleted. + */ + void deleteOffer(Long offerId); + + /** + * If no ID is contained creates the {@link OfferEto} for the first time. Else it updates the {@link OfferEto} with + * given ID. If no {@link OfferEto} with given ID is present, an exception will be thrown. + * + * @param offer the {@link OfferEto} to persist. + * @return the generated/updated offer + */ + OfferEto saveOffer(@Valid OfferEto offer); /** * Gets a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product} using its entity identifier. @@ -118,4 +188,37 @@ public interface UcFindProduct { * @return the {@link Blob} that contains the data */ Blob findProductPictureBlob(Long productId); + + /** + * If no ID is contained creates the {@link ProductEto} for the first time. Else it updates the {@link ProductEto} + * with given ID. If no {@link ProductEto} with given ID is present, an exception will be thrown. + * + * @param product the {@link ProductEto} to persist. + * @return the persisted {@link ProductEto}. + */ + ProductEto saveProduct(ProductEto product); + + /** + * Deletes a {@link ProductEto}. + * + * @param productId is the ID of the {@link ProductEto} to delete + */ + void deleteProduct(Long productId); + + /** + * Updates the picture of the product. + * + * @param productId is the ID of the {@link ProductEto} to update the picture + * @param blob is the binary representation of the picture + * @param binaryObjectEto is the mimeType of the blob + */ + void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto); + + /** + * Deletes the Picture of the {@link ProductEto}. + * + * @param productId is the ID of the {@link ProductEto} to delte the picture + */ + void deleteProductPicture(Long productId); + } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java similarity index 57% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java index b7e162c7c..632c4ffb0 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/DrinkEto.java @@ -1,69 +1,46 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink; - -/** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for a {@link Drink}. - * - * @author jozitz - */ -public class DrinkEto extends ProductEto implements Drink { - - private static final long serialVersionUID = 1L; - - private boolean alcoholic; - - /** - * The constructor. - */ - public DrinkEto() { - - super(); - } - - /** - * Returns the field 'alcoholic'. - * - * @return Value of alcoholic - */ - public boolean isAlcoholic() { - - return this.alcoholic; - } - - /** - * Sets the field 'alcoholic'. - * - * @param alcoholic New value for alcoholic - */ - public void setAlcoholic(boolean alcoholic) { - - this.alcoholic = alcoholic; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + (this.alcoholic ? 1 : 0); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - DrinkEto other = (DrinkEto) obj; - if (this.alcoholic != other.alcoholic) { - return false; - } - return true; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink; + +/** + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for a {@link Drink}. + * + * @author jozitz + */ +public class DrinkEto extends ProductEto implements Drink { + + private static final long serialVersionUID = 1L; + + private boolean alcoholic; + + /** + * The constructor. + */ + public DrinkEto() { + + super(); + } + + /** + * Returns the field 'alcoholic'. + * + * @return Value of alcoholic + */ + @Override + public boolean isAlcoholic() { + + return this.alcoholic; + } + + /** + * Sets the field 'alcoholic'. + * + * @param alcoholic New value for alcoholic + */ + @Override + public void setAlcoholic(boolean alcoholic) { + + this.alcoholic = alcoholic; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java similarity index 79% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java index faf7fd422..7629adbd2 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MealEto.java @@ -3,7 +3,7 @@ import io.oasp.gastronomy.restaurant.offermanagement.common.api.Meal; /** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for a {@link Meal}. + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for a {@link Meal}. * * @author jozitz */ diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java new file mode 100644 index 000000000..e6bfa356d --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/MenuItemEto.java @@ -0,0 +1,50 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.MenuItem; +import io.oasp.module.basic.common.api.to.AbstractEto; + +/** + * The {@link AbstractEto ETO} for a {@link MenuItem}. + * + * @author jozitz + */ +public abstract class MenuItemEto extends AbstractEto implements MenuItem { + + private static final long serialVersionUID = 1L; + + private String name; + + private String description; + + /** + * The constructor. + */ + public MenuItemEto() { + + super(); + } + + @Override + public String getName() { + + return this.name; + } + + @Override + public void setName(String name) { + + this.name = name; + } + + @Override + public String getDescription() { + + return this.description; + } + + @Override + public void setDescription(String description) { + + this.description = description; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java index 704221545..8fc4994be 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferCto.java @@ -1,6 +1,6 @@ package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractCto; +import io.oasp.module.basic.common.api.to.AbstractCto; /** * The {@link AbstractCto CTO} for an {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer}. diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java similarity index 53% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java index c35855449..101113430 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferEto.java @@ -1,160 +1,109 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.validation.NotNegativeMoney; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferState; - -import java.util.Objects; - -/** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for an {@link Offer}. - * - * @author jozitz - */ -public class OfferEto extends MenuItemEto implements Offer { - - private static final long serialVersionUID = 1L; - - private Long number; - - @NotNegativeMoney - private Money currentPrice; - - private Long mealId; - - private Long drinkId; - - private Long sideDishId; - - private OfferState state; - - /** - * The constructor. - */ - public OfferEto() { - - super(); - } - - @Override - public Long getNumber() { - - return this.number; - } - - @Override - public void setNumber(Long number) { - - this.number = number; - } - - @Override - public Money getPrice() { - - return this.currentPrice; - } - - @Override - public void setPrice(Money currentPrice) { - - this.currentPrice = currentPrice; - } - - @Override - public Long getMealId() { - - return this.mealId; - } - - @Override - public void setMealId(Long mealId) { - - this.mealId = mealId; - } - - @Override - public Long getDrinkId() { - - return this.drinkId; - } - - @Override - public void setDrinkId(Long drinkId) { - - this.drinkId = drinkId; - } - - @Override - public Long getSideDishId() { - - return this.sideDishId; - } - - @Override - public void setSideDishId(Long sideDishId) { - - this.sideDishId = sideDishId; - } - - @Override - public OfferState getState() { - - return this.state; - } - - @Override - public void setState(OfferState state) { - - this.state = state; - } - - @Override - public int hashCode() { - - final Integer prime = 31; - Integer result = super.hashCode(); - result = prime * result + ((this.number == null) ? 0 : this.number.hashCode()); - result = prime * result + ((this.currentPrice == null) ? 0 : this.currentPrice.hashCode()); - result = prime * result + ((this.drinkId == null) ? 0 : this.drinkId.hashCode()); - result = prime * result + ((this.mealId == null) ? 0 : this.mealId.hashCode()); - result = prime * result + ((this.sideDishId == null) ? 0 : this.sideDishId.hashCode()); - result = prime * result + ((this.state == null) ? 0 : this.state.ordinal()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - OfferEto other = (OfferEto) obj; - if (!Objects.equals(this.number, other.number)) { - return false; - } - if (!Objects.equals(this.currentPrice, other.currentPrice)) { - return false; - } - if (!Objects.equals(this.drinkId, other.drinkId)) { - return false; - } - if (!Objects.equals(this.mealId, other.mealId)) { - return false; - } - if (!Objects.equals(this.sideDishId, other.sideDishId)) { - return false; - } - if (this.state != other.state) { - return false; - } - return true; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.validation.NotNegativeMoney; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferState; + +/** + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for an {@link Offer}. + * + * @author jozitz + */ +public class OfferEto extends MenuItemEto implements Offer { + + private static final long serialVersionUID = 1L; + + private Long number; + + @NotNegativeMoney + private Money currentPrice; + + private Long mealId; + + private Long drinkId; + + private Long sideDishId; + + private OfferState state; + + /** + * The constructor. + */ + public OfferEto() { + + super(); + } + + @Override + public Long getNumber() { + + return this.number; + } + + @Override + public void setNumber(Long number) { + + this.number = number; + } + + @Override + public Money getPrice() { + + return this.currentPrice; + } + + @Override + public void setPrice(Money currentPrice) { + + this.currentPrice = currentPrice; + } + + @Override + public Long getMealId() { + + return this.mealId; + } + + @Override + public void setMealId(Long mealId) { + + this.mealId = mealId; + } + + @Override + public Long getDrinkId() { + + return this.drinkId; + } + + @Override + public void setDrinkId(Long drinkId) { + + this.drinkId = drinkId; + } + + @Override + public Long getSideDishId() { + + return this.sideDishId; + } + + @Override + public void setSideDishId(Long sideDishId) { + + this.sideDishId = sideDishId; + } + + @Override + public OfferState getState() { + + return this.state; + } + + @Override + public void setState(OfferState state) { + + this.state = state; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java similarity index 91% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java index 3ff6459ea..38da1afd7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferFilter.java @@ -1,158 +1,159 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * {@link AbstractTransferObject TO} to filter {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer}s. - * - * @author etomety - */ -public class OfferFilter extends AbstractTransferObject { - - private static final long serialVersionUID = 1L; - - private Long mealId; - - private Long sideDishId; - - private Long drinkId; - - private Money minPrice; - - private Money maxPrice; - - /** - * The constructor. - */ - public OfferFilter() { - - // initialize - this.mealId = null; - this.sideDishId = null; - this.drinkId = null; - this.minPrice = null; - this.maxPrice = null; - } - - /* - * Constructor - */ - /** - * @param mealId Id of a meal as a Long - * @param sideDishId Id of a Sidedish as a Long - * @param drinkId Id of a Drink as a Long - * @param minPrice minimal price for the filtered offers or null to ignore - * @param maxPrice maximal price for the filtered offers or null to ignore - */ - public OfferFilter(Long mealId, Long sideDishId, Long drinkId, Money minPrice, Money maxPrice) { - - this.mealId = mealId; - this.sideDishId = sideDishId; - this.drinkId = drinkId; - this.minPrice = minPrice; - this.maxPrice = maxPrice; - } - - /** - * Returns the field 'mealId'. - * - * @return Value of mealId - */ - public Long getMealId() { - - return this.mealId; - } - - /** - * Returns the field 'sideDishId'. - * - * @return Value of sideDishId - */ - public Long getSideDishId() { - - return this.sideDishId; - } - - /** - * Returns the field 'drinkId'. - * - * @return Value of drinkId - */ - public Long getDrinkId() { - - return this.drinkId; - } - - /** - * Returns the field 'minPrice'. - * - * @return Value of minPrice - */ - public Money getMinPrice() { - - return this.minPrice; - } - - /** - * Returns the field 'maxPrice'. - * - * @return Value of maxPrice - */ - public Money getMaxPrice() { - - return this.maxPrice; - } - - /** - * Sets the field 'mealId'. - * - * @param mealId New value for mealId - */ - public void setMealId(Long mealId) { - - this.mealId = mealId; - } - - /** - * Sets the field 'sideDishId'. - * - * @param sideDishId New value for sideDishId - */ - public void setSideDishId(Long sideDishId) { - - this.sideDishId = sideDishId; - } - - /** - * Sets the field 'drinkId'. - * - * @param drinkId New value for drinkId - */ - public void setDrinkId(Long drinkId) { - - this.drinkId = drinkId; - } - - /** - * Sets the field 'minPrice'. - * - * @param minPrice New value for minPrice - */ - public void setMinPrice(Money minPrice) { - - this.minPrice = minPrice; - } - - /** - * Sets the field 'maxPrice'. - * - * @param maxPrice New value for maxPrice - */ - public void setMaxPrice(Money maxPrice) { - - this.maxPrice = maxPrice; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.module.basic.common.api.to.AbstractTo; + +import net.sf.mmm.util.transferobject.api.AbstractTransferObject; + +/** + * {@link AbstractTransferObject TO} to filter {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer}s. + * + * @author etomety + */ +public class OfferFilter extends AbstractTo { + + private static final long serialVersionUID = 1L; + + private Long mealId; + + private Long sideDishId; + + private Long drinkId; + + private Money minPrice; + + private Money maxPrice; + + /** + * The constructor. + */ + public OfferFilter() { + + // initialize + this.mealId = null; + this.sideDishId = null; + this.drinkId = null; + this.minPrice = null; + this.maxPrice = null; + } + + /* + * Constructor + */ + /** + * @param mealId Id of a meal as a Long + * @param sideDishId Id of a Sidedish as a Long + * @param drinkId Id of a Drink as a Long + * @param minPrice minimal price for the filtered offers or null to ignore + * @param maxPrice maximal price for the filtered offers or null to ignore + */ + public OfferFilter(Long mealId, Long sideDishId, Long drinkId, Money minPrice, Money maxPrice) { + + this.mealId = mealId; + this.sideDishId = sideDishId; + this.drinkId = drinkId; + this.minPrice = minPrice; + this.maxPrice = maxPrice; + } + + /** + * Returns the field 'mealId'. + * + * @return Value of mealId + */ + public Long getMealId() { + + return this.mealId; + } + + /** + * Returns the field 'sideDishId'. + * + * @return Value of sideDishId + */ + public Long getSideDishId() { + + return this.sideDishId; + } + + /** + * Returns the field 'drinkId'. + * + * @return Value of drinkId + */ + public Long getDrinkId() { + + return this.drinkId; + } + + /** + * Returns the field 'minPrice'. + * + * @return Value of minPrice + */ + public Money getMinPrice() { + + return this.minPrice; + } + + /** + * Returns the field 'maxPrice'. + * + * @return Value of maxPrice + */ + public Money getMaxPrice() { + + return this.maxPrice; + } + + /** + * Sets the field 'mealId'. + * + * @param mealId New value for mealId + */ + public void setMealId(Long mealId) { + + this.mealId = mealId; + } + + /** + * Sets the field 'sideDishId'. + * + * @param sideDishId New value for sideDishId + */ + public void setSideDishId(Long sideDishId) { + + this.sideDishId = sideDishId; + } + + /** + * Sets the field 'drinkId'. + * + * @param drinkId New value for drinkId + */ + public void setDrinkId(Long drinkId) { + + this.drinkId = drinkId; + } + + /** + * Sets the field 'minPrice'. + * + * @param minPrice New value for minPrice + */ + public void setMinPrice(Money minPrice) { + + this.minPrice = minPrice; + } + + /** + * Sets the field 'maxPrice'. + * + * @param maxPrice New value for maxPrice + */ + public void setMaxPrice(Money maxPrice) { + + this.maxPrice = maxPrice; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSearchCriteriaTo.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSearchCriteriaTo.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/OfferSortBy.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java similarity index 85% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java index 228b54dcf..5f20f7cdb 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductEto.java @@ -3,7 +3,7 @@ import io.oasp.gastronomy.restaurant.offermanagement.common.api.Product; /** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for a {@link Product}. + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for a {@link Product}. * * @author hohwille * @author jozitz diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java similarity index 72% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java index 13380d2e2..f76946c9a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductFilter.java @@ -1,142 +1,110 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; - -/** - * {@link AbstractTransferObject TO} to filter {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product - * products}. - * - * @author etomety - */ -public class ProductFilter extends AbstractTransferObject { - - private static final long serialVersionUID = 1L; - - private boolean fetchDrinks; - - private boolean fetchMeals; - - private boolean fetchSideDishes; - - /** - * Constructor. - * - * Initializes the private fields fetchDrinks, fetchMeals and fetchSideDishes with {@code false}. So nothing is - * fetched by default. - */ - public ProductFilter() { - - this.fetchDrinks = false; - this.fetchMeals = false; - this.fetchSideDishes = false; - } - - /** - * Constructor. - * - * @param fetchDrinks is the flag for getting {@link DrinkEto drinks} from db (set this to {@code true}) - * @param fetchMeals is the flag for getting {@link MealEto meals} from db (set this to {@code true}) - * @param fetchSideDishes is the flag for getting {@link SideDishEto side dishes} from db (set this to - * {@code true}) - */ - public ProductFilter(boolean fetchDrinks, boolean fetchMeals, boolean fetchSideDishes) { - - this.fetchDrinks = fetchDrinks; - this.fetchMeals = fetchMeals; - this.fetchSideDishes = fetchSideDishes; - } - - /** - * Returns the field 'fetchSideDishes'. - * - * @return Value of fetchSideDishes - */ - public boolean getFetchSideDishes() { - - return this.fetchSideDishes; - } - - /** - * Sets the field 'fetchSideDishes'. - * - * @param fetchSideDishes New value for fetchSideDishes - */ - public void setFetchSideDishes(boolean fetchSideDishes) { - - this.fetchSideDishes = fetchSideDishes; - } - - /** - * Returns the field 'fetchMeals'. - * - * @return Value of fetchMeals - */ - public boolean getFetchMeals() { - - return this.fetchMeals; - } - - /** - * Sets the field 'fetchMeals'. - * - * @param fetchMeals New value for fetchMeals - */ - public void setFetchMeals(boolean fetchMeals) { - - this.fetchMeals = fetchMeals; - } - - /** - * Returns the field 'fetchDrinks'. - * - * @return Value of fetchDrinks - */ - public boolean getFetchDrinks() { - - return this.fetchDrinks; - } - - /** - * Sets the field 'fetchDrinks'. - * - * @param fetchDrinks New value for fetchDrinks - */ - public void setFetchDrinks(boolean fetchDrinks) { - - this.fetchDrinks = fetchDrinks; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + (this.fetchDrinks ? 1 : 0); - result = prime * result + (this.fetchMeals ? 1 : 0); - result = prime * result + (this.fetchSideDishes ? 1 : 0); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - ProductFilter other = (ProductFilter) obj; - if (this.fetchDrinks != other.fetchDrinks) { - return false; - } - if (this.fetchMeals != other.fetchMeals) { - return false; - } - if (this.fetchSideDishes != other.fetchSideDishes) { - return false; - } - return true; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.module.basic.common.api.to.AbstractTo; + +import net.sf.mmm.util.transferobject.api.AbstractTransferObject; + +/** + * {@link AbstractTransferObject TO} to filter {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Product + * products}. + * + * @author etomety + */ +public class ProductFilter extends AbstractTo { + + private static final long serialVersionUID = 1L; + + private boolean fetchDrinks; + + private boolean fetchMeals; + + private boolean fetchSideDishes; + + /** + * Constructor. + * + * Initializes the private fields fetchDrinks, fetchMeals and fetchSideDishes with {@code false}. So nothing is + * fetched by default. + */ + public ProductFilter() { + + this.fetchDrinks = false; + this.fetchMeals = false; + this.fetchSideDishes = false; + } + + /** + * Constructor. + * + * @param fetchDrinks is the flag for getting {@link DrinkEto drinks} from db (set this to {@code true}) + * @param fetchMeals is the flag for getting {@link MealEto meals} from db (set this to {@code true}) + * @param fetchSideDishes is the flag for getting {@link SideDishEto side dishes} from db (set this to {@code true}) + */ + public ProductFilter(boolean fetchDrinks, boolean fetchMeals, boolean fetchSideDishes) { + + this.fetchDrinks = fetchDrinks; + this.fetchMeals = fetchMeals; + this.fetchSideDishes = fetchSideDishes; + } + + /** + * Returns the field 'fetchSideDishes'. + * + * @return Value of fetchSideDishes + */ + public boolean getFetchSideDishes() { + + return this.fetchSideDishes; + } + + /** + * Sets the field 'fetchSideDishes'. + * + * @param fetchSideDishes New value for fetchSideDishes + */ + public void setFetchSideDishes(boolean fetchSideDishes) { + + this.fetchSideDishes = fetchSideDishes; + } + + /** + * Returns the field 'fetchMeals'. + * + * @return Value of fetchMeals + */ + public boolean getFetchMeals() { + + return this.fetchMeals; + } + + /** + * Sets the field 'fetchMeals'. + * + * @param fetchMeals New value for fetchMeals + */ + public void setFetchMeals(boolean fetchMeals) { + + this.fetchMeals = fetchMeals; + } + + /** + * Returns the field 'fetchDrinks'. + * + * @return Value of fetchDrinks + */ + public boolean getFetchDrinks() { + + return this.fetchDrinks; + } + + /** + * Sets the field 'fetchDrinks'. + * + * @param fetchDrinks New value for fetchDrinks + */ + public void setFetchDrinks(boolean fetchDrinks) { + + this.fetchDrinks = fetchDrinks; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java similarity index 81% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java index 6cc7ead5a..20eae6786 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSearchCriteriaTo.java @@ -1,129 +1,130 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.module.jpa.common.api.to.SearchCriteriaTo; - -/** - * This is the {@link SearchCriteriaTo search criteria} {@link net.sf.mmm.util.transferobject.api.TransferObject TO} - * used to find {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.Product}s. - * - * If no boolean is set to true, no {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.Product}s will be - * found. - * - * @author lgoerlac - */ -public class ProductSearchCriteriaTo extends SearchCriteriaTo { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - private boolean fetchDrinks; - - private boolean fetchMeals; - - private boolean fetchSideDishes; - - private String name; - - private String description; - - /** - * The constructor. - */ - public ProductSearchCriteriaTo() { - - super(); - - this.fetchDrinks = true; - this.fetchMeals = true; - this.fetchSideDishes = true; - - } - - /** - * @return fetchDrinks - */ - public boolean isFetchDrinks() { - - return this.fetchDrinks; - } - - /** - * @param fetchDrinks the fetchDrinks to set - */ - public void setFetchDrinks(boolean fetchDrinks) { - - this.fetchDrinks = fetchDrinks; - } - - /** - * @return fetchMeals - */ - public boolean isFetchMeals() { - - return this.fetchMeals; - } - - /** - * @param fetchMeals the fetchMeals to set - */ - public void setFetchMeals(boolean fetchMeals) { - - this.fetchMeals = fetchMeals; - } - - /** - * @return fetchSideDishes - */ - public boolean isFetchSideDishes() { - - return this.fetchSideDishes; - } - - /** - * @param fetchSideDishes the fetchSideDishes to set - */ - public void setFetchSideDishes(boolean fetchSideDishes) { - - this.fetchSideDishes = fetchSideDishes; - } - - /** - * @return name - */ - public String getName() { - - return this.name; - } - - /** - * @param name the name to set - */ - public void setName(String name) { - - this.name = name; - } - - /** - * @return description - */ - public String getDescription() { - - return this.description; - } - - /** - * @param description the description to set - */ - public void setDescription(String description) { - - this.description = description; - } - - public String toStrink() { - - return "ProductSearchCriteriaTo [fetchDrinks=" + this.fetchDrinks + ", fetchMeals=" + this.fetchMeals - + ", fetchSideDishes=" + this.fetchSideDishes + ", name=" + this.name + ", description=" + this.description - + "]"; - } - -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Product; +import io.oasp.module.jpa.common.api.to.SearchCriteriaTo; + +/** + * This is the {@link SearchCriteriaTo search criteria} {@link net.sf.mmm.util.transferobject.api.TransferObject TO} + * used to find {@link Product}s. + * + * If no boolean is set to true, no {@link Product}s will be found. + * + * @author lgoerlac + */ +public class ProductSearchCriteriaTo extends SearchCriteriaTo { + + /** UID for serialization. */ + private static final long serialVersionUID = 1L; + + private boolean fetchDrinks; + + private boolean fetchMeals; + + private boolean fetchSideDishes; + + private String name; + + private String description; + + /** + * The constructor. + */ + public ProductSearchCriteriaTo() { + + super(); + + this.fetchDrinks = true; + this.fetchMeals = true; + this.fetchSideDishes = true; + + } + + /** + * @return fetchDrinks + */ + public boolean isFetchDrinks() { + + return this.fetchDrinks; + } + + /** + * @param fetchDrinks the fetchDrinks to set + */ + public void setFetchDrinks(boolean fetchDrinks) { + + this.fetchDrinks = fetchDrinks; + } + + /** + * @return fetchMeals + */ + public boolean isFetchMeals() { + + return this.fetchMeals; + } + + /** + * @param fetchMeals the fetchMeals to set + */ + public void setFetchMeals(boolean fetchMeals) { + + this.fetchMeals = fetchMeals; + } + + /** + * @return fetchSideDishes + */ + public boolean isFetchSideDishes() { + + return this.fetchSideDishes; + } + + /** + * @param fetchSideDishes the fetchSideDishes to set + */ + public void setFetchSideDishes(boolean fetchSideDishes) { + + this.fetchSideDishes = fetchSideDishes; + } + + /** + * @return name + */ + public String getName() { + + return this.name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + + this.name = name; + } + + /** + * @return description + */ + public String getDescription() { + + return this.description; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + + this.description = description; + } + + @Override + protected void toString(StringBuilder buffer) { + + buffer.append("ProductSearchCriteriaTo [fetchDrinks=" + this.fetchDrinks + ", fetchMeals=" + this.fetchMeals + + ", fetchSideDishes=" + this.fetchSideDishes + ", name=" + this.name + ", description=" + this.description + + "]"); + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java index 1a5b456f7..d6b210130 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/ProductSortBy.java @@ -1,65 +1,63 @@ -package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductSortByHitEntry; -import io.oasp.module.jpa.common.api.to.OrderDirection; - -// TODO mvielsac javadoc for class is missing - -/** - * - * @author erandres - */ -public class ProductSortBy { - private ProductSortByHitEntry sortByEntry; - - private OrderDirection orderBy; - - /** - * Constructor for {@link ProductSortBy}. - */ - public ProductSortBy() { - - this.sortByEntry = ProductSortByHitEntry.ID; - this.orderBy = OrderDirection.ASC; - } - - /** - * Returns the field 'sortByEntry'. - * - * @return Value of sortByEntry - */ - public ProductSortByHitEntry getSortByEntry() { - - return this.sortByEntry; - } - - /** - * Sets the field 'sortByEntry'. - * - * @param sortByEntry New value for sortByEntry - */ - public void setSortByEntry(ProductSortByHitEntry sortByEntry) { - - this.sortByEntry = sortByEntry; - } - - /** - * Returns the field 'orderBy'. - * - * @return Value of orderBy - */ - public OrderDirection getOrderBy() { - - return this.orderBy; - } - - /** - * Sets the field 'orderBy'. - * - * @param orderBy New value for orderBy - */ - public void setOrderBy(OrderDirection orderBy) { - - this.orderBy = orderBy; - } -} +package io.oasp.gastronomy.restaurant.offermanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductSortByHitEntry; +import io.oasp.module.jpa.common.api.to.OrderDirection; + +/** + * + * @author erandres + */ +public class ProductSortBy { + private ProductSortByHitEntry sortByEntry; + + private OrderDirection orderBy; + + /** + * Constructor for {@link ProductSortBy}. + */ + public ProductSortBy() { + + this.sortByEntry = ProductSortByHitEntry.ID; + this.orderBy = OrderDirection.ASC; + } + + /** + * Returns the field 'sortByEntry'. + * + * @return Value of sortByEntry + */ + public ProductSortByHitEntry getSortByEntry() { + + return this.sortByEntry; + } + + /** + * Sets the field 'sortByEntry'. + * + * @param sortByEntry New value for sortByEntry + */ + public void setSortByEntry(ProductSortByHitEntry sortByEntry) { + + this.sortByEntry = sortByEntry; + } + + /** + * Returns the field 'orderBy'. + * + * @return Value of orderBy + */ + public OrderDirection getOrderBy() { + + return this.orderBy; + } + + /** + * Sets the field 'orderBy'. + * + * @param orderBy New value for orderBy + */ + public void setOrderBy(OrderDirection orderBy) { + + this.orderBy = orderBy; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java similarity index 79% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java index 7eb3bcde5..af68a7e0d 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/api/to/SideDishEto.java @@ -3,7 +3,7 @@ import io.oasp.gastronomy.restaurant.offermanagement.common.api.SideDish; /** - * The {@link io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto ETO} for a {@link SideDish}. + * The {@link io.oasp.module.basic.common.api.to.AbstractEto ETO} for a {@link SideDish}. * * @author jozitz */ diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java new file mode 100644 index 000000000..04a4d7107 --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/logic/impl/OffermanagementImpl.java @@ -0,0 +1,503 @@ +package io.oasp.gastronomy.restaurant.offermanagement.logic.impl; + +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.logic.api.to.BinaryObjectEto; +import io.oasp.gastronomy.restaurant.general.logic.base.AbstractComponentFacade; +import io.oasp.gastronomy.restaurant.general.logic.base.UcManageBinaryObject; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.Product; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.ProductType; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.exception.OfferEmptyException; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.ProductEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.MealDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.OfferDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.ProductDao; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.SideDishDao; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferCto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +import java.sql.Blob; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.inject.Named; +import javax.transaction.Transactional; +import javax.validation.Valid; + +import net.sf.mmm.util.exception.api.ObjectMismatchException; +import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation class for {@link Offermanagement}. + * + * @author loverbec + */ +@Named +@Transactional +public class OffermanagementImpl extends AbstractComponentFacade implements Offermanagement { + + private static final Logger LOG = LoggerFactory.getLogger(OffermanagementImpl.class); + + /** @see #getOfferDao() */ + private OfferDao offerDao; + + /** @see #setProductDao(ProductDao) */ + private ProductDao productDao; + + /** @see #setMealDao(MealDao) */ + private MealDao mealDao; + + /** @see #setDrinkDao(DrinkDao) */ + private DrinkDao drinkDao; + + /** @see #setSideDishDao(SideDishDao) */ + private SideDishDao sideDishDao; + + /** **/ + private UcManageBinaryObject ucManageBinaryObject; + + /** + * The constructor. + */ + public OffermanagementImpl() { + + super(); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public OfferEto findOffer(Long id) { + + LOG.debug("Get OfferEto with id '{}' from database.", id); + return getBeanMapper().map(getOfferDao().findOne(id), OfferEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public OfferCto findOfferCto(Long id) { + + LOG.debug("Get OfferCTO with id '{}' from database.", id); + OfferCto result = new OfferCto(); + // offer + OfferEto offerEto = findOffer(id); + if (offerEto == null) { + return null; + } + result.setOffer(offerEto); + // meal + Long mealId = offerEto.getMealId(); + if (mealId != null) { + result.setMeal(findMeal(mealId)); + } + // drink + Long drinkId = offerEto.getDrinkId(); + if (drinkId != null) { + result.setDrink(findDrink(drinkId)); + } + // sideDish + Long sideDishId = offerEto.getSideDishId(); + if (sideDishId != null) { + result.setSideDish(findSideDish(sideDishId)); + } + return result; + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public List findAllOffers() { + + LOG.debug("Get all offers from database."); + return getBeanMapper().mapList(getOfferDao().findAll(), OfferEto.class); + } + + @Override + @RolesAllowed({ PermissionConstants.FIND_OFFER, PermissionConstants.FIND_PRODUCT }) + public boolean isProductInUseByOffer(ProductEto product) { + + LOG.debug("Get all offers from database for the given product with id '" + product.getId() + "'."); + + List persistedOffers = findAllOffers(); + + /* + * Check the occurrence of a product within all offers. Therefore, only check for a instance of a product type + * product type. + */ + ProductType productType = null; + + if (product instanceof DrinkEto) { + LOG.debug("The given product is an instance of Drink '" + product.getDescription() + "', id '" + product.getId() + + "'. Check all Offer-Drinks for that given occurrence."); + productType = ProductType.DRINK; + } else if (product instanceof MealEto) { + LOG.debug("The given product is an instance of Meal '" + product.getDescription() + "', id '" + product.getId() + + "'. Check all Offer-Meals for that given occurrence."); + productType = ProductType.MEAL; + } else if (product instanceof SideDishEto) { + LOG.debug("The given product is an instance of SideDish '" + product.getDescription() + "', id '" + + product.getId() + "'. Check all Offer-SideDishes for that given occurrence."); + productType = ProductType.SIDEDISH; + } + + if (productType == null) { + LOG.debug("The given product not in use by an offer."); + return false; + } + + for (OfferEto offer : persistedOffers) { + + if (productType.isDrink()) { + if (Objects.equals(offer.getDrinkId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + + } + + if (productType.isMeal()) { + if (Objects.equals(offer.getMealId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + } + + if (productType.isSideDish()) { + if (Objects.equals(offer.getSideDishId(), product.getId())) { + LOG.debug("The given product is in use by offer with id '" + offer.getId() + "', description '" + + offer.getDescription() + "'."); + return true; + } + continue; + } + } + + LOG.debug("The given product not in use by an offer."); + return false; + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { + + List offers = getOfferDao().findOffersFiltered(offerFilterBo, sortBy); + LOG.debug("'" + offers.size() + "' offers fetched."); + + List offerBos = new ArrayList<>(offers.size()); + for (OfferEntity o : offers) { + offerBos.add(getBeanMapper().map(o, OfferEto.class)); + } + return offerBos; + } + + @Override + @RolesAllowed(PermissionConstants.DELETE_OFFER) + public void deleteOffer(Long offerId) { + + getOfferDao().delete(offerId); + } + + @Override + @RolesAllowed(PermissionConstants.SAVE_OFFER) + public OfferEto saveOffer(@Valid OfferEto offer) { + + Objects.requireNonNull(offer, "offer"); + + if ((offer.getMealId() == null) && (offer.getDrinkId() == null) && (offer.getSideDishId() == null)) { + throw new OfferEmptyException(offer); + } else { + OfferEntity persistedOffer = getOfferDao().save(getBeanMapper().map(offer, OfferEntity.class)); + return getBeanMapper().map(persistedOffer, OfferEto.class); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public ProductEto findProduct(Long id) { + + LOG.debug("Get Product with id '" + id + "' from database."); + ProductEntity product = getProductDao().findOne(id); + if (product == null) { + return null; + } else { + return getBeanMapper().map(product, ProductEto.class); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public MealEto findMeal(Long id) { + + ProductEto product = findProduct(id); + try { + return (MealEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, MealEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public DrinkEto findDrink(Long id) { + + ProductEto product = findProduct(id); + try { + return (DrinkEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, DrinkEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public SideDishEto findSideDish(Long id) { + + ProductEto product = findProduct(id); + try { + return (SideDishEto) product; + } catch (ClassCastException e) { + throw new ObjectMismatchException(product, SideDishEto.class, e); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllProducts() { + + LOG.debug("Get all products from database."); + return getBeanMapper().mapList(getProductDao().findAll(), ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllMeals() { + + LOG.debug("Get all meals with from database."); + return getBeanMapper().mapList(this.mealDao.findAll(), MealEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllDrinks() { + + LOG.debug("Get all drinks with from database."); + return getBeanMapper().mapList(this.drinkDao.findAll(), DrinkEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public List findAllSideDishes() { + + LOG.debug("Get all sidedishes with from database."); + return getBeanMapper().mapList(this.sideDishDao.findAll(), SideDishEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public List findProductsFiltered(ProductFilter productFilterBo, ProductSortBy sortBy) { + + LOG.debug("Fetch filtered offers."); + return getBeanMapper().mapList(getProductDao().findProductsFiltered(productFilterBo, sortBy), ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public BinaryObjectEto findProductPicture(Long productId) { + + ProductEto product = findProduct(productId); + if (product != null) { + return getUcManageBinaryObject().findBinaryObject(product.getPictureId()); + } else { + return null; + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) + public Blob findProductPictureBlob(Long productId) { + + ProductEto product = findProduct(productId); + if (product != null) { + return getUcManageBinaryObject().getBinaryObjectBlob(product.getPictureId()); + } else { + return null; + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT_PICTURE) + public ProductEto findProductByRevision(Long id, Number revision) { + + LOG.debug("Get Product with id '" + id + "' and revision '" + revision + "' from database."); + ProductEntity product = getProductDao().load(id, revision); + if (product == null) { + return null; + } else { + return getBeanMapper().map(product, ProductEto.class); + } + } + + @Override + @RolesAllowed(PermissionConstants.SAVE_PRODUCT) + public ProductEto saveProduct(ProductEto product) { + + Objects.requireNonNull(product, "product"); + + ProductEntity persistedProduct = getProductDao().save(getBeanMapper().map(product, ProductEntity.class)); + return getBeanMapper().map(persistedProduct, ProductEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.DELETE_PRODUCT) + public void deleteProduct(Long productId) { + + getProductDao().delete(productId); + } + + @Override + @RolesAllowed(PermissionConstants.SAVE_PRODUCT_PICTURE) + public void updateProductPicture(Long productId, Blob blob, BinaryObjectEto binaryObjectEto) { + + ProductEntity product = getProductDao().findOne(productId); + if (product != null) { + binaryObjectEto = getUcManageBinaryObject().saveBinaryObject(blob, binaryObjectEto); + product.setPictureId(binaryObjectEto.getId()); + getProductDao().save(product); + } else { + throw new ObjectNotFoundUserException(Product.class, productId); + } + + } + + @Override + @RolesAllowed(PermissionConstants.DELETE_PRODUCT_PICTURE) + public void deleteProductPicture(Long productId) { + + ProductEntity product = getProductDao().findOne(productId); + if (product != null) { + getUcManageBinaryObject().deleteBinaryObject(product.getPictureId()); + } + } + + @Override + @RolesAllowed(PermissionConstants.FIND_OFFER) + public PaginatedListTo findOfferEtos(OfferSearchCriteriaTo criteria) { + + criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); + PaginatedListTo offers = getOfferDao().findOffers(criteria); + return mapPaginatedEntityList(offers, OfferEto.class); + } + + @Override + @RolesAllowed(PermissionConstants.FIND_PRODUCT) + public PaginatedListTo findProductEtos(ProductSearchCriteriaTo criteria) { + + criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT); + PaginatedListTo products = getProductDao().findProducts(criteria); + return mapPaginatedEntityList(products, ProductEto.class); + } + + /** + * @return {@link OfferDao} instance. + */ + public OfferDao getOfferDao() { + + return this.offerDao; + } + + /** + * Sets the field 'offerDao'. + * + * @param offerDao New value for offerDao + */ + @Inject + public void setOfferDao(OfferDao offerDao) { + + this.offerDao = offerDao; + } + + /** + * @param ucManageBinaryObject the ucManageBinaryObject to set + */ + @Inject + public void setUcManageBinaryObject(UcManageBinaryObject ucManageBinaryObject) { + + this.ucManageBinaryObject = ucManageBinaryObject; + } + + /** + * @return ucManageBinaryObject + */ + public UcManageBinaryObject getUcManageBinaryObject() { + + return this.ucManageBinaryObject; + } + + /** + * @return productDao + */ + public ProductDao getProductDao() { + + return this.productDao; + } + + /** + * Sets the field 'productDao'. + * + * @param productDao New value for productDao + */ + @Inject + public void setProductDao(ProductDao productDao) { + + this.productDao = productDao; + } + + /** + * @param mealDao the {@link MealDao} to {@link Inject}. + */ + @Inject + public void setMealDao(MealDao mealDao) { + + this.mealDao = mealDao; + } + + /** + * @param drinkDao the {@link DrinkDao} to {@link Inject}. + */ + @Inject + public void setDrinkDao(DrinkDao drinkDao) { + + this.drinkDao = drinkDao; + } + + /** + * @param sideDishDao the {@link SideDishDao} to {@link Inject}. + */ + @Inject + public void setSideDishDao(SideDishDao sideDishDao) { + + this.sideDishDao = sideDishDao; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java similarity index 89% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java index ebbb78a58..ebe589378 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/service/impl/rest/OffermanagementRestServiceImpl.java @@ -13,8 +13,6 @@ import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSearchCriteriaTo; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductSortBy; import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.SideDishEto; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindOffer; -import io.oasp.gastronomy.restaurant.offermanagement.logic.api.usecase.UcFindProduct; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.io.ByteArrayInputStream; @@ -38,12 +36,12 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.Multipart; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; -import org.springframework.transaction.annotation.Transactional; /** * This class contains methods for REST calls. Some URI structures may seem depricated, but in fact are not. See the @@ -55,7 +53,6 @@ @Named("OffermanagementRestService") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) -@Transactional public class OffermanagementRestServiceImpl { private Offermanagement offermanagement; @@ -77,7 +74,7 @@ public void setOffermanagement(Offermanagement offerManagement) { */ @GET @Path("/offer/{id}") - public OfferEto getOffer(@PathParam("id") Long id) { + public OfferEto getOffer(@PathParam("id") long id) { return this.offermanagement.findOffer(id); } @@ -204,7 +201,7 @@ public List getAllSideDishes() { */ @DELETE @Path("/offer/{id}") - public void deleteOffer(@PathParam("id") Long id) { + public void deleteOffer(@PathParam("id") long id) { this.offermanagement.deleteOffer(id); } @@ -218,7 +215,7 @@ public void deleteOffer(@PathParam("id") Long id) { */ @GET @Path("/product/{id}/{revision}") - public ProductEto findProductByRevision(@PathParam("id") Long id, @PathParam("revision") Long revision) { + public ProductEto findProductByRevision(@PathParam("id") long id, @PathParam("revision") Long revision) { if (revision != null) { return this.offermanagement.findProductByRevision(id, revision); @@ -235,7 +232,7 @@ public ProductEto findProductByRevision(@PathParam("id") Long id, @PathParam("re */ @GET @Path("/product/{id}") - public ProductEto findProduct(@PathParam("id") Long id) { + public ProductEto findProduct(@PathParam("id") long id) { return this.offermanagement.findProduct(id); } @@ -264,7 +261,7 @@ public void updateProduct(ProductEto product) { */ @GET @Path("/product/{id}/inuse") - public boolean isProductInUseByOffer(@PathParam("id") Long id) { + public boolean isProductInUseByOffer(@PathParam("id") long id) { return this.offermanagement.isProductInUseByOffer(findProduct(id)); } @@ -276,7 +273,7 @@ public boolean isProductInUseByOffer(@PathParam("id") Long id) { */ @DELETE @Path("/product/{id}") - public void deleteProduct(@PathParam("id") Long id) { + public void deleteProduct(@PathParam("id") long id) { this.offermanagement.deleteProduct(id); } @@ -315,7 +312,7 @@ public List getFilteredProducts(ProductFilter productFilter, @PathPa @Consumes("multipart/mixed") @POST @Path("/product/{id}/picture") - public void updateProductPicture(@PathParam("id") Long productId, + public void updateProductPicture(@PathParam("id") long productId, @Multipart(value = "binaryObjectEto", type = MediaType.APPLICATION_JSON) BinaryObjectEto binaryObjectEto, @Multipart(value = "blob", type = MediaType.APPLICATION_OCTET_STREAM) InputStream picture) throws SerialException, SQLException, IOException { @@ -344,6 +341,23 @@ public MultipartBody getProductPicture(@PathParam("id") long productId) throws S } + @SuppressWarnings("javadoc") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @GET + @Path("/product/{id}/rawpicture") + @Deprecated + public Response getProductRawPicture(@PathParam("id") long productId) throws SQLException, IOException { + + Blob blob = this.offermanagement.findProductPictureBlob(productId); + if (blob != null) { + byte[] data = IOUtils.readBytesFromStream(blob.getBinaryStream()); + BinaryObjectEto metadata = this.offermanagement.findProductPicture(productId); + return Response.ok(new ByteArrayInputStream(data)).header("Content-Type", metadata.getMimeType()).build(); + } else { + return Response.noContent().build(); + } + } + @SuppressWarnings("javadoc") @DELETE @Path("/product/{id}/picture") @@ -353,7 +367,7 @@ public void deleteProductPicture(long productId) { } /** - * Delegates to {@link UcFindOffer#findOfferEtos}. + * Delegates to {@link Offermanagement#findOfferEtos}. * * @param searchCriteriaTo the pagination and search criteria to be used for finding offers. * @return the {@link PaginatedListTo list} of matching {@link OfferEto}s. @@ -366,7 +380,7 @@ public PaginatedListTo findOfferEtosByPost(OfferSearchCriteriaTo searc } /** - * Delegates to {@link UcFindProduct#findProductEtos}. + * Delegates to {@link Offermanagement#findProductEtos}. * * @param searchCriteriaTo the pagination and search criteria to be used for finding products. * @return the {@link PaginatedListTo list} of matching {@link ProductEto}s. diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/processor/BillProcessor.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/processor/BillProcessor.java new file mode 100644 index 000000000..2f66efe3d --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/processor/BillProcessor.java @@ -0,0 +1,37 @@ +package io.oasp.gastronomy.restaurant.salesmanagement.batch.impl.billexport.processor; + +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillCto; + +import javax.inject.Inject; + +import org.springframework.batch.item.ItemProcessor; + +/** + * Implementation of ItemProcessor. It finds BillCto by id and returns it. + * + * @author ABIELEWI + */ +public class BillProcessor implements ItemProcessor { + + private Salesmanagement salesmanagement; + + /** + * {@inheritDoc} + */ + @Override + public BillCto process(Long item) throws Exception { + + return this.salesmanagement.findBill(item); + } + + /** + * @param salesmanagement the salesmanagement to set + */ + @Inject + public void setSalesmanagement(Salesmanagement salesmanagement) { + + this.salesmanagement = salesmanagement; + } + +} diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/writer/BillCompositeWriter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/writer/BillCompositeWriter.java new file mode 100644 index 000000000..da38d90eb --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/writer/BillCompositeWriter.java @@ -0,0 +1,131 @@ +package io.oasp.gastronomy.restaurant.salesmanagement.batch.impl.billexport.writer; + +import static com.google.common.collect.Lists.newArrayList; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillCto; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.BillEto; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.file.ResourceAwareItemWriterItemStream; +import org.springframework.batch.item.file.transform.LineAggregator; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; + +/** + * Implementation of ItemWriter. It gets BillCto and writes it in csv format into file. + * + * @author ABIELEWI + */ +public class BillCompositeWriter implements ResourceAwareItemWriterItemStream, InitializingBean { + + private static final Logger LOG = LoggerFactory.getLogger(BillCompositeWriter.class); + + private ResourceAwareItemWriterItemStream delegate; + + private LineAggregator billLineAggregator; + + private LineAggregator positionLineAggregator; + + private Resource resource; + + /** + * {@inheritDoc} + */ + @Override + public void afterPropertiesSet() throws Exception { + + LOG.debug("Resource: " + this.resource); + + this.delegate.setResource(this.resource); + + } + + /** + * {@inheritDoc} + */ + @Override + public void open(ExecutionContext executionContext) throws ItemStreamException { + + this.delegate.open(executionContext); + + LOG.debug("Bill composite writed opened"); + } + + /** + * {@inheritDoc} + */ + @Override + public void update(ExecutionContext executionContext) throws ItemStreamException { + + this.delegate.update(executionContext); + } + + /** + * {@inheritDoc} + */ + @Override + public void close() throws ItemStreamException { + + this.delegate.close(); + + LOG.debug("Bill composite writed closed"); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(List items) throws Exception { + + List lines = newArrayList(); + for (BillCto item : items) { + String billLine = this.billLineAggregator.aggregate(item.getBill()); + for (OrderPositionEto position : item.getPositions()) { + String positionLine = this.positionLineAggregator.aggregate(position); + lines.add(billLine + "," + positionLine); + LOG.debug("Write bill line, offer name: " + position.getOfferName()); + } + } + this.delegate.write(lines); + } + + /** + * {@inheritDoc} + */ + + @Override + public void setResource(Resource resource) { + + this.resource = resource; + } + + /** + * @param delegate the delegate to set + */ + public void setDelegate(ResourceAwareItemWriterItemStream delegate) { + + this.delegate = delegate; + } + + /** + * @param billLineAggregator the billLineAggregator to set + */ + public void setBillLineAggregator(LineAggregator billLineAggregator) { + + this.billLineAggregator = billLineAggregator; + } + + /** + * @param positionLineAggregator the positionLineAggregator to set + */ + public void setPositionLineAggregator(LineAggregator positionLineAggregator) { + + this.positionLineAggregator = positionLineAggregator; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java similarity index 89% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java index 05139a6ca..cb8ffe7ed 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Bill.java @@ -2,6 +2,7 @@ import io.oasp.gastronomy.restaurant.general.common.api.ApplicationEntity; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.validation.NotNegativeMoney; import java.util.List; @@ -25,6 +26,7 @@ public interface Bill extends ApplicationEntity { /** * @return the tip (voluntary payment in addition to {@link #getTotal() total amount}). */ + @NotNegativeMoney(message = "The tip must not be negative!") Money getTip(); /** diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java index cc73864f9..e8eabaf26 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/Order.java @@ -1,5 +1,7 @@ package io.oasp.gastronomy.restaurant.salesmanagement.common.api; +import javax.validation.constraints.NotNull; + import io.oasp.gastronomy.restaurant.general.common.api.ApplicationEntity; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; @@ -17,6 +19,7 @@ public interface Order extends ApplicationEntity { * {@link io.oasp.gastronomy.restaurant.tablemanagement.common.api.Table} where this {@link Order} was * disposed. */ + @NotNull long getTableId(); /** @@ -27,6 +30,7 @@ public interface Order extends ApplicationEntity { /** * @return the {@link OrderState state} of this {@link Order}. */ + @NotNull OrderState getState(); /** diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java similarity index 85% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java index 5b6243262..b46cdeff5 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/OrderPosition.java @@ -1,8 +1,12 @@ package io.oasp.gastronomy.restaurant.salesmanagement.common.api; +import javax.validation.constraints.NotNull; + import io.oasp.gastronomy.restaurant.general.common.api.ApplicationEntity; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.validation.NotNegativeMoney; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; /** * This is the interface for an {@link OrderPosition}. @@ -14,6 +18,7 @@ public interface OrderPosition extends ApplicationEntity { /** * @return the {@link Order#getId ID} of the {@link Order} this {@link OrderPosition} belongs to. */ + @NotNull Long getOrderId(); /** @@ -39,6 +44,7 @@ public interface OrderPosition extends ApplicationEntity { * key and might not point to an existing * {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} for historic {@link OrderPosition}s. */ + @NotNull Long getOfferId(); /** @@ -52,6 +58,7 @@ public interface OrderPosition extends ApplicationEntity { * This is stored redundant so that it is still available later if the * {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} has been changed. */ + @NotNull String getOfferName(); /** @@ -62,19 +69,32 @@ public interface OrderPosition extends ApplicationEntity { /** * @return the current {@link OrderPositionState state}. */ + @NotNull OrderPositionState getState(); + /** + * @return the current {@link ProductOrderState state}. + */ + ProductOrderState getDrinkState(); + /** * @param state the new {@link #getState() state}. */ void setState(OrderPositionState state); + /** + * @param drinkState the new {@link #getDrinkState() state}. + */ + void setDrinkState(ProductOrderState drinkState); + /** * @return the price of the {@link #getOfferId() associated} * {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer}. This is stored redundant so that it * is still available later if the {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Offer} has * been changed. */ + @NotNull + @NotNegativeMoney Money getPrice(); /** diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/CreditCardType.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/CreditCardType.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/CreditCardType.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/CreditCardType.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderPositionState.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderPositionState.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderPositionState.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderPositionState.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderState.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderState.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderState.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/OrderState.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/PaymentStatus.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/PaymentStatus.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/PaymentStatus.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/PaymentStatus.java diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/ProductOrderState.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/ProductOrderState.java new file mode 100644 index 000000000..79661ff9b --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/datatype/ProductOrderState.java @@ -0,0 +1,55 @@ +package io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype; + +/** + * Represents the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition#getDrinkState() state} + * of an {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}. + * + * @author oelsabba + */ +public enum ProductOrderState { + + /** + * The initial state of a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink }. + */ + ORDERED, + + /** + * The state of a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} that has been prepared by the + * bar keeper and can be served by the waiter. + */ + PREPARED, + + /** + * The state of a {@link io.oasp.gastronomy.restaurant.offermanagement.common.api.Drink} that has been delivered to + * the table by the waiter. + */ + DELIVERED; + + /** + * @return true if the {@link io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity} + * is ordered + */ + public boolean isOrdered() { + + return (this == ORDERED); + } + + /** + * @return true if the {@link io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity} + * is prepared + */ + public boolean isPrepared() { + + return (this == PREPARED); + } + + /** + * @return true if the {@link io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity} + * is delivered. + */ + public boolean isDelivered() { + + return (this == DELIVERED); + } + +} \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/exception/ChangeTableIllegalStateCombinationException.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/exception/ChangeTableIllegalStateCombinationException.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/exception/ChangeTableIllegalStateCombinationException.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/common/api/exception/ChangeTableIllegalStateCombinationException.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java similarity index 92% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java index c9558e24a..731f37718 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/BillEntity.java @@ -1,24 +1,28 @@ package io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Bill; - import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.ManyToMany; +import javax.persistence.Table; import javax.persistence.Transient; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Bill; + /** * {@link ApplicationPersistenceEntity Entity} that represents the {@link Bill} related to one or multiple * {@OrderPosition order positions}. * * @author etomety */ -@Entity(name = "Bill") +@Entity +@Table(name = "Bill") public class BillEntity extends ApplicationPersistenceEntity implements Bill { private static final long serialVersionUID = 1L; @@ -43,6 +47,7 @@ public BillEntity() { * @return the {@link List} of {@link OrderPositionEntity} objects associated with this {@link BillEntity}. */ @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "Bill_OrderPosition", joinColumns = { @JoinColumn(name = "Bill_id") }) public List getOrderPositions() { return this.orderPositions; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java index f63c643d8..dc09e4c12 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderEntity.java @@ -17,7 +17,7 @@ * * @author rjoeris */ -@Entity(name = "Order") +@Entity // Order is a reserved word in SQL/RDBMS and can not be used as table name @Table(name = "RestaurantOrder") public class OrderEntity extends ApplicationPersistenceEntity implements Order { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java similarity index 85% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java index a5a559a39..3781adb37 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/OrderPositionEntity.java @@ -4,13 +4,16 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.Table; import javax.persistence.Transient; +import javax.validation.constraints.NotNull; /** * {@link ApplicationPersistenceEntity Entity} that represents a single {@link OrderPosition position} of an @@ -18,7 +21,8 @@ * * @author hohwille */ -@Entity(name = "OrderPosition") +@Entity +@Table(name = "OrderPosition") public class OrderPositionEntity extends ApplicationPersistenceEntity implements OrderPosition { private static final long serialVersionUID = 1L; @@ -33,6 +37,8 @@ public class OrderPositionEntity extends ApplicationPersistenceEntity implements private OrderPositionState state; + private ProductOrderState drinkState; + private Money price; private String comment; @@ -51,6 +57,7 @@ public OrderPositionEntity() { */ @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "order_id") + @NotNull public OrderEntity getOrder() { return this.order; @@ -159,4 +166,23 @@ public void setComment(String comment) { this.comment = comment; } + /** + * {@inheritDoc} + */ + @Override + public ProductOrderState getDrinkState() { + + return this.drinkState; + } + + /** + * {@inheritDoc} + */ + @Override + public void setDrinkState(ProductOrderState drinkState) { + + this.drinkState = drinkState; + + } + } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/BillDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/BillDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/BillDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/BillDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderPositionDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderPositionDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderPositionDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/api/dao/OrderPositionDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java similarity index 93% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java index eaeab4fb2..506416b80 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/OrderPositionDaoImpl.java @@ -4,6 +4,7 @@ import io.oasp.gastronomy.restaurant.general.dataaccess.base.dao.ApplicationDaoImpl; import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderPositionEntity; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.dao.OrderPositionDao; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionSearchCriteriaTo; @@ -68,6 +69,10 @@ public List findOrderPositions(OrderPositionSearchCriteriaT if (state != null) { query.where(Alias.$(orderPosition.getState()).eq(state)); } + ProductOrderState drinkState = criteria.getDrinkState(); + if (drinkState != null) { + query.where(Alias.$(orderPosition.getDrinkState()).eq(drinkState)); + } if (criteria.isMealOrSideDish()) { OfferEntity offer = Alias.alias(OfferEntity.class); EntityPathBase offerAlias = Alias.$(offer); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/Salesmanagement.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/Salesmanagement.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/Salesmanagement.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/Salesmanagement.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BankPaymentData.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BankPaymentData.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BankPaymentData.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BankPaymentData.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java similarity index 56% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java index 4a55a9cc3..1b3b57001 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillCto.java @@ -1,98 +1,65 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractCto; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * {@link AbstractCto CTO} for an {@link #getBill() bill} with its {@link #getPositions() positions}. - * - * @author jmetzler - */ -public class BillCto extends AbstractCto { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - private BillEto bill; - - private List positions; - - /** - * The constructor. - */ - public BillCto() { - - super(); - } - - /** - * @return positions - */ - public List getPositions() { - - if (this.positions == null) { - this.positions = new ArrayList<>(); - } - return this.positions; - } - - /** - * @param positions the positions to set - */ - public void setPositions(List positions) { - - this.positions = positions; - } - - /** - * @param bill the bill to set - */ - public void setBill(BillEto bill) { - - this.bill = bill; - } - - /** - * @return bill - */ - public BillEto getBill() { - - return this.bill; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.bill == null) ? 0 : this.bill.hashCode()); - result = prime * result + ((this.positions == null) ? 0 : this.positions.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - BillCto other = (BillCto) obj; - if (Objects.equals(this.bill, other.bill)) { - return false; - } - if (Objects.equals(this.positions, other.positions)) { - return false; - } - return true; - } - -} +package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; + +import io.oasp.module.basic.common.api.to.AbstractCto; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link AbstractCto CTO} for an {@link #getBill() bill} with its {@link #getPositions() positions}. + * + * @author jmetzler + */ +public class BillCto extends AbstractCto { + + /** UID for serialization. */ + private static final long serialVersionUID = 1L; + + private BillEto bill; + + private List positions; + + /** + * The constructor. + */ + public BillCto() { + + super(); + } + + /** + * @return positions + */ + public List getPositions() { + + if (this.positions == null) { + this.positions = new ArrayList<>(); + } + return this.positions; + } + + /** + * @param positions the positions to set + */ + public void setPositions(List positions) { + + this.positions = positions; + } + + /** + * @param bill the bill to set + */ + public void setBill(BillEto bill) { + + this.bill = bill; + } + + /** + * @return bill + */ + public BillEto getBill() { + + return this.bill; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java similarity index 53% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java index 8262dbb9a..25e4d2abd 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/BillEto.java @@ -1,123 +1,82 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Bill; - -import java.util.List; -import java.util.Objects; - -/** - * {@link AbstractEto ETO} for {@link Bill}. - * - * @author etomety - */ -public class BillEto extends AbstractEto implements Bill { - - private static final long serialVersionUID = 1L; - - private boolean payed; - - private List orderPositionIds; - - private Money total; - - private Money tip; - - /** - * The constructor. - */ - public BillEto() { - - super(); - } - - @Override - public List getOrderPositionIds() { - - return this.orderPositionIds; - } - - @Override - public void setOrderPositionIds(List orderPositions) { - - this.orderPositionIds = orderPositions; - } - - @Override - public Money getTotal() { - - return this.total; - } - - @Override - public void setTotal(Money total) { - - this.total = total; - } - - @Override - public Money getTip() { - - return this.tip; - } - - @Override - public void setTip(Money tip) { - - this.tip = tip; - } - - @Override - public boolean isPayed() { - - return this.payed; - } - - @Override - public void setPayed(boolean payed) { - - this.payed = payed; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.orderPositionIds == null) ? 0 : this.orderPositionIds.hashCode()); - result = prime * result + (this.payed ? 1 : 0); - result = prime * result + ((this.tip == null) ? 0 : this.tip.hashCode()); - result = prime * result + ((this.total == null) ? 0 : this.total.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - BillEto other = (BillEto) obj; - if (Objects.equals(this.orderPositionIds, other.orderPositionIds)) { - return false; - } - if (this.payed != other.payed) { - return false; - } - if (Objects.equals(this.total, other.total)) { - return false; - } - if (Objects.equals(this.tip, other.tip)) { - return false; - } - return true; - } - -} +package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Bill; +import io.oasp.module.basic.common.api.to.AbstractEto; + +import java.util.List; + +/** + * {@link AbstractEto ETO} for {@link Bill}. + * + * @author etomety + */ +public class BillEto extends AbstractEto implements Bill { + + private static final long serialVersionUID = 1L; + + private boolean payed; + + private List orderPositionIds; + + private Money total; + + private Money tip; + + /** + * The constructor. + */ + public BillEto() { + + super(); + } + + @Override + public List getOrderPositionIds() { + + return this.orderPositionIds; + } + + @Override + public void setOrderPositionIds(List orderPositions) { + + this.orderPositionIds = orderPositions; + } + + @Override + public Money getTotal() { + + return this.total; + } + + @Override + public void setTotal(Money total) { + + this.total = total; + } + + @Override + public Money getTip() { + + return this.tip; + } + + @Override + public void setTip(Money tip) { + + this.tip = tip; + } + + @Override + public boolean isPayed() { + + return this.payed; + } + + @Override + public void setPayed(boolean payed) { + + this.payed = payed; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/CreditCardPaymentData.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/CreditCardPaymentData.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/CreditCardPaymentData.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/CreditCardPaymentData.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java similarity index 57% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java index d0ce9b9b2..cebf8faf6 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderCto.java @@ -1,10 +1,9 @@ package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractCto; +import io.oasp.module.basic.common.api.to.AbstractCto; import java.util.ArrayList; import java.util.List; -import java.util.Objects; /** * {@link AbstractCto CTO} for an {@link #getOrder() order} with its {@link #getPositions() positions}. @@ -62,37 +61,4 @@ public void setPositions(List positions) { this.positions = positions; } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.order == null) ? 0 : this.order.hashCode()); - result = prime * result + ((this.positions == null) ? 0 : this.positions.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - OrderCto other = (OrderCto) obj; - if (Objects.equals(this.order, other.order)) { - return false; - } - if (Objects.equals(this.positions, other.positions)) { - return false; - } - return true; - } - } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java similarity index 53% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java index eb11089e2..797e2eda5 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderEto.java @@ -1,90 +1,55 @@ -/** - * - */ -package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Order; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; - -/** - * {@link AbstractEto ETO} for an {@link Order}. - * - * @author rjoeris - */ -public class OrderEto extends AbstractEto implements Order { - - private static final long serialVersionUID = 1L; - - private long tableId; - - private OrderState state; - - /** - * The constructor. - */ - public OrderEto() { - - this.state = OrderState.OPEN; - } - - @Override - public long getTableId() { - - return this.tableId; - } - - @Override - public void setTableId(long tableId) { - - this.tableId = tableId; - } - - @Override - public OrderState getState() { - - return this.state; - } - - @Override - public void setState(OrderState state) { - - this.state = state; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.state == null) ? 0 : this.state.hashCode()); - result = prime * result + (int) this.tableId; - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - OrderEto other = (OrderEto) obj; - if (getId() == other.getId()) { - return false; - } - if (this.state != other.state) { - return false; - } - if (this.tableId != other.tableId) { - return false; - } - return true; - } - -} +/** + * + */ +package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Order; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; +import io.oasp.module.basic.common.api.to.AbstractEto; + +/** + * {@link AbstractEto ETO} for an {@link Order}. + * + * @author rjoeris + */ +public class OrderEto extends AbstractEto implements Order { + + private static final long serialVersionUID = 1L; + + private long tableId; + + private OrderState state; + + /** + * The constructor. + */ + public OrderEto() { + + this.state = OrderState.OPEN; + } + + @Override + public long getTableId() { + + return this.tableId; + } + + @Override + public void setTableId(long tableId) { + + this.tableId = tableId; + } + + @Override + public OrderState getState() { + + return this.state; + } + + @Override + public void setState(OrderState state) { + + this.state = state; + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java similarity index 57% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java index 540f95c9d..1a42d8089 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionEto.java @@ -1,182 +1,157 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition; -import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; - -import java.util.Objects; - -/** - * {@link AbstractEto ETO} for an {@link OrderPosition}. - * - * @author jozitz - */ -public class OrderPositionEto extends AbstractEto implements OrderPosition { - - private static final long serialVersionUID = 1L; - - private Long orderId; - - private Long cookId; - - private Long offerId; - - private String offerName; - - private OrderPositionState state; - - private Money price; - - private String comment; - - /** - * The constructor. - */ - public OrderPositionEto() { - - this.state = OrderPositionState.ORDERED; - } - - @Override - public Long getOrderId() { - - return this.orderId; - } - - @Override - public void setOrderId(Long orderId) { - - this.orderId = orderId; - } - - @Override - public Long getCookId() { - - return this.cookId; - } - - @Override - public void setCookId(Long cookId) { - - this.cookId = cookId; - } - - @Override - public Long getOfferId() { - - return this.offerId; - } - - @Override - public void setOfferId(Long offerId) { - - this.offerId = offerId; - } - - @Override - public String getOfferName() { - - return this.offerName; - } - - @Override - public void setOfferName(String offerName) { - - this.offerName = offerName; - } - - @Override - public OrderPositionState getState() { - - return this.state; - } - - @Override - public void setState(OrderPositionState state) { - - this.state = state; - } - - @Override - public Money getPrice() { - - return this.price; - } - - @Override - public void setPrice(Money price) { - - this.price = price; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.orderId == null) ? 0 : this.orderId.hashCode()); - result = prime * result + ((this.cookId == null) ? 0 : this.cookId.hashCode()); - result = prime * result + ((this.offerName == null) ? 0 : this.offerName.hashCode()); - result = prime * result + ((this.offerId == null) ? 0 : this.offerId.hashCode()); - result = prime * result + ((this.comment == null) ? 0 : this.comment.hashCode()); - result = prime * result + ((this.price == null) ? 0 : this.price.hashCode()); - result = prime * result + ((this.state == null) ? 0 : this.state.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (obj == null) { - return false; - } - if (!super.equals(obj)) { - return false; - } - OrderPositionEto other = (OrderPositionEto) obj; - if (!Objects.equals(this.orderId, other.orderId)) { - return false; - } - if (!Objects.equals(this.cookId, other.cookId)) { - return false; - } - if (!Objects.equals(this.offerId, other.offerId)) { - return false; - } - if (!Objects.equals(this.offerName, other.offerName)) { - return false; - } - if (!Objects.equals(this.price, other.price)) { - return false; - } - if (!Objects.equals(this.comment, other.comment)) { - return false; - } - if (this.state != other.state) { - return false; - } - return true; - } - - /** - * Returns the field 'comment'. - * - * @return Comment as string - */ - public String getComment() { - - return this.comment; - } - - /** - * Sets the field 'comment'. - * - * @param comment new value for comment - */ - public void setComment(String comment) { - - this.comment = comment; - } - -} +package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; +import io.oasp.module.basic.common.api.to.AbstractEto; + +/** + * {@link AbstractEto ETO} for an {@link OrderPosition}. + * + * @author jozitz + */ +public class OrderPositionEto extends AbstractEto implements OrderPosition { + + private static final long serialVersionUID = 1L; + + private Long orderId; + + private Long cookId; + + private Long offerId; + + private String offerName; + + private OrderPositionState state; + + private ProductOrderState drinkState; + + private Money price; + + private String comment; + + /** + * The constructor. + */ + public OrderPositionEto() { + + this.state = OrderPositionState.ORDERED; + + } + + @Override + public Long getOrderId() { + + return this.orderId; + } + + @Override + public void setOrderId(Long orderId) { + + this.orderId = orderId; + } + + @Override + public Long getCookId() { + + return this.cookId; + } + + @Override + public void setCookId(Long cookId) { + + this.cookId = cookId; + } + + @Override + public Long getOfferId() { + + return this.offerId; + } + + @Override + public void setOfferId(Long offerId) { + + this.offerId = offerId; + } + + @Override + public String getOfferName() { + + return this.offerName; + } + + @Override + public void setOfferName(String offerName) { + + this.offerName = offerName; + } + + @Override + public OrderPositionState getState() { + + return this.state; + } + + @Override + public void setState(OrderPositionState state) { + + this.state = state; + } + + @Override + public Money getPrice() { + + return this.price; + } + + @Override + public void setPrice(Money price) { + + this.price = price; + } + + /** + * Returns the field 'comment'. + * + * @return Comment as string + */ + @Override + public String getComment() { + + return this.comment; + } + + /** + * Sets the field 'comment'. + * + * @param comment new value for comment + */ + @Override + public void setComment(String comment) { + + this.comment = comment; + } + + /** + * {@inheritDoc} + */ + @Override + public ProductOrderState getDrinkState() { + + return this.drinkState; + + } + + /** + * {@inheritDoc} + */ + @Override + public void setDrinkState(ProductOrderState drinkState) { + + this.drinkState = drinkState; + + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java similarity index 70% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java index b78069d28..7da8e197a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderPositionSearchCriteriaTo.java @@ -1,6 +1,7 @@ package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; import io.oasp.module.jpa.common.api.to.SearchCriteriaTo; /** @@ -16,6 +17,8 @@ public class OrderPositionSearchCriteriaTo extends SearchCriteriaTo { private OrderPositionState state; + private ProductOrderState drinkState; + private Long orderId; private Long cookId; @@ -46,10 +49,26 @@ public void setState(OrderPositionState orderPositionState) { this.state = orderPositionState; } + /** + * @return drinkState of the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition } + */ + public ProductOrderState getDrinkState() { + + return this.drinkState; + } + + /** + * @param drinkState the drinkState to set + */ + public void setDrinkState(ProductOrderState drinkState) { + + this.drinkState = drinkState; + } + /** * @return the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition#getOrderId() order ID} of - * the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s to find or - * {@code null} if no such criteria shall be added. + * the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s to find or {@code null} + * if no such criteria shall be added. */ public Long getOrderId() { @@ -66,8 +85,8 @@ public void setOrderId(Long orderId) { /** * @return the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition#getCookId() cook ID} of - * the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s to find or - * {@code null} if no such criteria shall be added. + * the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s to find or {@code null} + * if no such criteria shall be added. */ public Long getCookId() { @@ -83,9 +102,9 @@ public void setCookId(Long cookId) { } /** - * @return {@code true} if only {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s - * shall be found that have a meal or a side-dish associated (exclude drink only positions), - * {@code false} if no such criteria shall be added. + * @return {@code true} if only {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition}s shall + * be found that have a meal or a side-dish associated (exclude drink only positions), {@code false} if no + * such criteria shall be added. */ public boolean isMealOrSideDish() { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderSearchCriteriaTo.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/OrderSearchCriteriaTo.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/PaymentData.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/PaymentData.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/PaymentData.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/to/PaymentData.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcChangeTable.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcChangeTable.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcChangeTable.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcChangeTable.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java index 1099906d0..5359b3f82 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindBill.java @@ -17,5 +17,5 @@ public interface UcFindBill { * @param id is the {@link BillEto#getId() id} of the Bill to fetch. * @return the {@link BillCto bill} for the given id. */ - BillCto findBill(Long id); + BillCto findBill(long id); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java similarity index 92% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java index 801511a57..1baa9cadb 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrder.java @@ -37,10 +37,10 @@ public interface UcFindOrder { * This method returns an {@link OrderEto order}. * * @param orderId identifier of the searched {@link OrderEto order} - * @return the {@link OrderEto order} with the given identifier. Will be {@code null} if the {@link OrderEto - * order} does not exist. + * @return the {@link OrderEto order} with the given identifier. Will be {@code null} if the {@link OrderEto order} + * does not exist. */ - OrderEto findOrder(Long orderId); + OrderEto findOrder(long orderId); /** * This method returns a the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState#OPEN @@ -52,6 +52,6 @@ public interface UcFindOrder { * {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState#OPEN open} * {@link OrderEto#getState() state} or {@code null} if no such {@link OrderEto order} exists. */ - OrderEto findOpenOrderForTable(Long tableId); + OrderEto findOpenOrderForTable(long tableId); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java similarity index 86% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java index 3fb93d7ce..847a8f76a 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcFindOrderPosition.java @@ -15,10 +15,10 @@ public interface UcFindOrderPosition { /** * @param orderPositionId is the {@link OrderPositionEto#getId() ID} of the requested {@link OrderPositionEto}. - * @return the {@link OrderPositionEto} with the given ID. Will be {@code null} if the {@link OrderPositionEto} - * does not exist. + * @return the {@link OrderPositionEto} with the given ID. Will be {@code null} if the {@link OrderPositionEto} does + * not exist. */ - OrderPositionEto findOrderPosition(Long orderPositionId); + OrderPositionEto findOrderPosition(long orderPositionId); /** * @param orderId is the {@link io.oasp.gastronomy.restaurant.salesmanagement.common.api.Order#getId() ID} of the @@ -27,7 +27,7 @@ public interface UcFindOrderPosition { * @return the {@link List} of {@link OrderPositionEto}s {@link OrderPositionEto#getOrderId() associated} with the * given orderId. */ - List findOrderPositionsByOrderId(Long orderId); + List findOrderPositionsByOrderId(long orderId); /** * @param criteria the {@link OrderPositionSearchCriteriaTo}. @@ -40,6 +40,6 @@ public interface UcFindOrderPosition { * @return the {@link List} of all {@link OrderPositionEto}s {@link OrderPositionEto#getId() associated} with the * given orderId. Will be the empty {@link List} if no such {@link OrderPositionEto} exists. */ - List findOpenOrderPositionsByOrderId(Long orderId); + List findOpenOrderPositionsByOrderId(long orderId); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java index a7ae2c8e4..434767ff4 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageBill.java @@ -28,7 +28,7 @@ public interface UcManageBill { * * @param billId the ID of the {@link BillEto} that has to be deleted. */ - void deleteBill(Long billId); + void deleteBill(long billId); /** * This method provides the payment process. It provides the cash-only functionality without any additional diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java similarity index 74% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java index 399de4361..befb06502 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrder.java @@ -2,7 +2,9 @@ import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderCto; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; /** * Interface of UcMangeOrder to centralize documentation and signatures of methods. @@ -18,7 +20,7 @@ public interface UcManageOrder { * @param order the {@link OrderCto} to persist. * @return the persisted {@link OrderCto}. */ - OrderCto saveOrder(OrderCto order); + OrderCto saveOrder(@NotNull OrderCto order); /** * If no ID is contained creates the {@link OrderEto} for the first time. Else it updates the {@link OrderEto} with @@ -27,18 +29,11 @@ public interface UcManageOrder { * @param order the {@link OrderEto} to persist. * @return the persisted {@link OrderEto}. */ - OrderEto saveOrder(OrderEto order); - - /** - * Persists new {@link OrderEto} with table ID set to ID of the given {@link TableEto}. - * - * @param table - * @return The persisted {@link OrderEto}. - */ - OrderEto saveOrder(TableEto table); + OrderEto saveOrder(@NotNull @Valid OrderEto order); /** * @param id is the {@link OrderEto#getId() ID} of the order to delete. */ - void deleteOrder(Long id); + void deleteOrder(long id); + } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java similarity index 91% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java index e42e2dcbb..8ef828089 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/api/usecase/UcManageOrderPosition.java @@ -1,5 +1,7 @@ package io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase; +import javax.validation.Valid; + import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; @@ -28,6 +30,6 @@ public interface UcManageOrderPosition { * @param orderPosition is the {@link OrderPositionEto} to persist. * @return the saved {@link OrderPositionEto}. */ - OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition); + OrderPositionEto saveOrderPosition(@Valid OrderPositionEto orderPosition); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractBillUc.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractBillUc.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractBillUc.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractBillUc.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderPositionUc.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderPositionUc.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderPositionUc.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderPositionUc.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderUc.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderUc.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderUc.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/base/usecase/AbstractOrderUc.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java similarity index 92% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java index 943c900ec..c296aa693 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesmanagementImpl.java @@ -20,13 +20,13 @@ import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageBill; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageOrder; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageOrderPosition; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.util.List; import javax.inject.Inject; import javax.inject.Named; +import javax.transaction.Transactional; /** * This is the implementation of {@link Salesmanagement}. @@ -34,6 +34,7 @@ * @author hohwille */ @Named +@Transactional public class SalesmanagementImpl extends AbstractComponentFacade implements Salesmanagement { private UcFindOrderPosition ucFindOrderPosition; @@ -129,7 +130,7 @@ public void setUcChangeTable(UcChangeTable ucChangeTable) { } @Override - public OrderEto findOrder(Long id) { + public OrderEto findOrder(long id) { return this.ucFindOrder.findOrder(id); } @@ -153,7 +154,7 @@ public OrderCto findOrderCto(OrderEto order) { } @Override - public OrderEto findOpenOrderForTable(Long tableId) { + public OrderEto findOpenOrderForTable(long tableId) { return this.ucFindOrder.findOpenOrderForTable(tableId); } @@ -172,7 +173,7 @@ public OrderPositionEto createOrderPosition(OfferEto offer, OrderEto order, Stri } @Override - public OrderPositionEto findOrderPosition(Long orderPositionId) { + public OrderPositionEto findOrderPosition(long orderPositionId) { return this.ucFindOrderPosition.findOrderPosition(orderPositionId); } @@ -184,13 +185,13 @@ public List findOrderPositions(OrderPositionSearchCriteriaTo c } @Override - public List findOrderPositionsByOrderId(Long orderId) { + public List findOrderPositionsByOrderId(long orderId) { return this.ucFindOrderPosition.findOrderPositionsByOrderId(orderId); } @Override - public List findOpenOrderPositionsByOrderId(Long orderId) { + public List findOpenOrderPositionsByOrderId(long orderId) { return this.ucFindOrderPosition.findOpenOrderPositionsByOrderId(orderId); } @@ -208,20 +209,20 @@ public PaymentStatus doPayment(BillEto bill, PaymentData paymentData) { } @Override - public BillCto findBill(Long id) { + public BillCto findBill(long id) { return this.ucFindBill.findBill(id); } @Override - public void deleteBill(Long billId) { + public void deleteBill(long billId) { this.ucManageBill.deleteBill(billId); } @Override - public void deleteOrder(Long id) { + public void deleteOrder(long id) { this.ucManageOrder.deleteOrder(id); } @@ -238,12 +239,6 @@ public OrderEto saveOrder(OrderEto order) { return this.ucManageOrder.saveOrder(order); } - @Override - public OrderEto saveOrder(TableEto table) { - - return this.ucManageOrder.saveOrder(table); - } - @Override public OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition) { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentAdapter.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentAdapter.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentAdapter.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentAdapter.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentTransactionData.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentTransactionData.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentTransactionData.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/PaymentTransactionData.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/impl/PaymentAdapterImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/impl/PaymentAdapterImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/impl/PaymentAdapterImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/paymentadapter/impl/PaymentAdapterImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcChangeTableImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcChangeTableImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcChangeTableImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcChangeTableImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java index ce2dfcbf9..d27cc0e67 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindBillImpl.java @@ -34,7 +34,7 @@ public class UcFindBillImpl extends AbstractBillUc implements UcFindBill { @Override @RolesAllowed(PermissionConstants.FIND_BILL) - public BillCto findBill(Long id) { + public BillCto findBill(long id) { LOG.debug("Get Bill with id '" + id + "' from database."); BillCto billCto = new BillCto(); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java similarity index 97% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java index b9bfe9b15..f9a0d4bd4 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderImpl.java @@ -37,7 +37,7 @@ public class UcFindOrderImpl extends AbstractOrderUc implements UcFindOrder { @Override @RolesAllowed(PermissionConstants.FIND_ORDER) - public OrderEto findOrder(Long orderId) { + public OrderEto findOrder(long orderId) { LOG.debug("Get order."); return getBeanMapper().map(getOrderDao().findOne(orderId), OrderEto.class); @@ -82,7 +82,7 @@ public OrderCto findOrderCto(OrderEto order) { @Override @RolesAllowed(PermissionConstants.FIND_ORDER) - public OrderEto findOpenOrderForTable(Long tableId) { + public OrderEto findOpenOrderForTable(long tableId) { OrderEntity order = getOrderDao().findOpenOrderByTable(tableId); return getBeanMapper().map(order, OrderEto.class); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java index 92036b7e4..ec0aa6573 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcFindOrderPositionImpl.java @@ -29,7 +29,7 @@ public class UcFindOrderPositionImpl extends AbstractOrderPositionUc implements @Override @RolesAllowed(PermissionConstants.FIND_ORDER_POSITION) - public OrderPositionEto findOrderPosition(Long orderPositionId) { + public OrderPositionEto findOrderPosition(long orderPositionId) { LOG.debug("Get order position."); OrderPositionEntity orderPositionEntities = getOrderPositionDao().findOne(orderPositionId); @@ -39,7 +39,7 @@ public OrderPositionEto findOrderPosition(Long orderPositionId) { @Override @RolesAllowed(PermissionConstants.FIND_ORDER_POSITION) - public List findOrderPositionsByOrderId(Long orderId) { + public List findOrderPositionsByOrderId(long orderId) { List positions = getOrderPositionDao().findOrderPositionsByOrder(orderId); return getBeanMapper().mapList(positions, OrderPositionEto.class); @@ -47,7 +47,7 @@ public List findOrderPositionsByOrderId(Long orderId) { @Override @RolesAllowed(PermissionConstants.FIND_ORDER_POSITION) - public List findOpenOrderPositionsByOrderId(Long orderId) { + public List findOpenOrderPositionsByOrderId(long orderId) { LOG.debug("Get all open order positions for order id '" + orderId + "'."); return getBeanMapper() diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java similarity index 99% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java index f25c4bcd0..e13455af1 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageBillImpl.java @@ -140,7 +140,7 @@ private BillEto update(BillEto bill) { @Override @RolesAllowed(PermissionConstants.DELETE_BILL) - public void deleteBill(Long billId) { + public void deleteBill(long billId) { getBillDao().delete(billId); } @@ -185,13 +185,9 @@ public PaymentStatus doPayment(BillEto bill, PaymentData paymentDataDebitor) { if (PaymentStatus.SUCCESS == status) { bill.setPayed(true); - for (Long orderPositionId : bill.getOrderPositionIds()) { - this.salesmanagement.findOrderPosition(orderPositionId).setState(OrderPositionState.PAYED); - } - } // Step4: Return a PaymentStatus diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java similarity index 57% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java index c60af947b..d72be43e7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderImpl.java @@ -3,6 +3,7 @@ import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; import io.oasp.gastronomy.restaurant.general.common.api.exception.IllegalEntityStateException; import io.oasp.gastronomy.restaurant.general.logic.api.UseCase; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.Order; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderEntity; @@ -12,7 +13,6 @@ import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageOrder; import io.oasp.gastronomy.restaurant.salesmanagement.logic.base.usecase.AbstractOrderUc; -import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableEto; import java.util.Collections; import java.util.List; @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; /** * Implementation of {@link UcManageOrder}. @@ -34,6 +35,7 @@ */ @Named @UseCase +@Validated public class UcManageOrderImpl extends AbstractOrderUc implements UcManageOrder { /** Logger instance. */ @@ -60,32 +62,72 @@ public void setSalesmanagement(Salesmanagement salesmanagement) { @Override @RolesAllowed(PermissionConstants.SAVE_ORDER) - public OrderEto saveOrder(TableEto table) { - - Objects.requireNonNull(table, "table"); - - OrderEntity order = new OrderEntity(); - order.setTableId(table.getId()); - getOrderDao().save(order); - - LOG.debug("The order with id '" + order.getId() + "' has been created. It's linked with table id '" + table.getId() - + "'."); + public OrderEto saveOrder(OrderEto order) { - return getBeanMapper().map(order, OrderEto.class); + return saveOrder(order, null); } - @Override - @RolesAllowed(PermissionConstants.SAVE_ORDER) - public OrderEto saveOrder(OrderEto order) { + private OrderEto saveOrder(OrderEto order, List positions) { Objects.requireNonNull(order, "order"); - + Long orderId = order.getId(); + if (orderId == null) { + OrderState state = order.getState(); + if (state != OrderState.OPEN) { + throw new IllegalEntityStateException(order, state); + } + } else { + OrderEntity currentOrder = getOrderDao().find(orderId); + verifyUpdate(currentOrder, order, positions); + } OrderEntity orderEntity = getBeanMapper().map(order, OrderEntity.class); orderEntity = getOrderDao().save(orderEntity); LOG.debug("Saved order with id {}.", orderEntity.getId()); return getBeanMapper().map(orderEntity, OrderEto.class); } + /** + * @param currentOrder is the current {@link Order} from the persistence. + * @param updateOrder is the new {@link Order} to update to. + * @param positions the {@link List} of {@link OrderPositionEto positions} or {@code null} if undefined. + */ + private void verifyUpdate(Order currentOrder, Order updateOrder, List positions) { + + if (currentOrder.getTableId() != updateOrder.getTableId()) { + LOG.info("Changing order from table-id {} to table-id {}", currentOrder.getTableId(), updateOrder.getTableId()); + } + verifyOrderStateChange(updateOrder, currentOrder.getState(), updateOrder.getState(), positions); + } + + /** + * Verifies if an update of the {@link OrderPositionState} is legal. + * + * @param updateOrder the new {@link Order} to update to. + * @param currentState the old/current {@link OrderState} of the {@link Order}. + * @param newState new {@link OrderState} of the {@link Order} to be updated to. + * @param positions the {@link List} of {@link OrderPositionEto positions} or {@code null} if undefined. + */ + private void verifyOrderStateChange(Order updateOrder, OrderState currentState, OrderState newState, + List positions) { + + if (currentState == newState) { + return; + } + if (newState == OrderState.CLOSED) { + if (positions == null) { + throw new IllegalEntityStateException(updateOrder, currentState, newState); + } + // we can only close an order if all its positions are closed... + for (OrderPositionEto position : positions) { + OrderPositionState positionState = position.getState(); + if ((positionState == null) || !positionState.isClosed()) { + IllegalEntityStateException cause = new IllegalEntityStateException(position, positionState); + throw new IllegalEntityStateException(cause, updateOrder, currentState, newState); + } + } + } + } + @Override @RolesAllowed(PermissionConstants.SAVE_ORDER) public OrderCto saveOrder(OrderCto order) { @@ -94,31 +136,24 @@ public OrderCto saveOrder(OrderCto order) { OrderEto orderEto = order.getOrder(); Long orderId = orderEto.getId(); - OrderEntity currentOrder = null; List currentOrderPositionList; if (orderId == null) { currentOrderPositionList = Collections.emptyList(); } else { - currentOrder = getOrderDao().find(orderId); // we could add a relation OrderEntity.positions of type List... currentOrderPositionList = this.salesmanagement.findOrderPositionsByOrderId(orderId); } - validateOrderState(order, currentOrder); - - OrderEntity orderEntity = getBeanMapper().map(orderEto, OrderEntity.class); - getOrderDao().save(orderEntity); + List positions = order.getPositions(); + orderEto = saveOrder(orderEto, positions); if (orderId == null) { - orderId = orderEntity.getId(); + orderId = orderEto.getId(); } - OrderEto savedOrder = getBeanMapper().map(orderEntity, OrderEto.class); OrderCto result = new OrderCto(); - result.setOrder(savedOrder); + result.setOrder(orderEto); // we can not use hibernate (Cascade and Delete orphaned) as we need to validate and react on them... - List positionList = order.getPositions(); - - List positions2DeleteList = getEntities2Delete(currentOrderPositionList, positionList); + List positions2DeleteList = getEntities2Delete(currentOrderPositionList, positions); List savedPositionList = result.getPositions(); if (positions2DeleteList.size() > 0) { LOG.warn("Marking {} number of order position(s) as cancelled that are missing in update of order with id {}", @@ -126,57 +161,27 @@ public OrderCto saveOrder(OrderCto order) { for (OrderPositionEto position : positions2DeleteList) { // only logically delete, actually the client should still send the cancelled positions... position.setState(OrderPositionState.CANCELLED); - this.salesmanagement.saveOrderPosition(position); + OrderPositionEto updatedOrderPosition = this.salesmanagement.saveOrderPosition(position); + savedPositionList.add(updatedOrderPosition); } - savedPositionList.addAll(positions2DeleteList); } - for (OrderPositionEto position : positionList) { + for (OrderPositionEto position : positions) { Long positionOrderId = position.getOrderId(); if (positionOrderId == null) { position.setOrderId(orderId); } else if (!positionOrderId.equals(orderId)) { throw new ObjectMismatchException(positionOrderId, orderId, "position.orderId"); } - savedPositionList.add(this.salesmanagement.saveOrderPosition(position)); + OrderPositionEto updatedOrderPosition = this.salesmanagement.saveOrderPosition(position); + savedPositionList.add(updatedOrderPosition); } return result; } - /** - * @param order is the {@link OrderCto} to save or update. - * @param targetOrder is the existing {@link OrderEntity} or {@code null} in case of a new {@link OrderCto} to - * save. - */ - private void validateOrderState(OrderCto order, OrderEntity targetOrder) { - - OrderEto orderEto = order.getOrder(); - List positionList = order.getPositions(); - // int positionCount = positionList.size(); - OrderState newState = orderEto.getState(); - if (targetOrder == null) { - // new order - if (newState != OrderState.OPEN) { - throw new IllegalEntityStateException(order, newState); - } - } else { - // update existing targetOrder - if (newState == OrderState.CLOSED) { - // we can only close an order if all its positions are closed... - for (OrderPositionEto position : positionList) { - OrderPositionState positionState = position.getState(); - if ((positionState == null) || !positionState.isClosed()) { - IllegalEntityStateException cause = new IllegalEntityStateException(position, positionState); - throw new IllegalEntityStateException(cause, order, OrderState.CLOSED); - } - } - } - } - } - @Override @RolesAllowed(PermissionConstants.DELETE_ORDER) - public void deleteOrder(Long id) { + public void deleteOrder(long id) { getOrderDao().delete(id); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java similarity index 61% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java index 1e4343e33..a1833967f 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/usecase/UcManageOrderPositionImpl.java @@ -1,5 +1,17 @@ package io.oasp.gastronomy.restaurant.salesmanagement.logic.impl.usecase; +import java.util.Objects; + +import javax.annotation.security.RolesAllowed; +import javax.inject.Inject; +import javax.inject.Named; + +import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; + import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; import io.oasp.gastronomy.restaurant.general.common.api.exception.IllegalEntityStateException; import io.oasp.gastronomy.restaurant.general.common.api.exception.IllegalPropertyChangeException; @@ -10,6 +22,7 @@ import io.oasp.gastronomy.restaurant.salesmanagement.common.api.OrderPosition; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderEntity; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.OrderPositionEntity; import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement; @@ -18,17 +31,6 @@ import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.usecase.UcManageOrderPosition; import io.oasp.gastronomy.restaurant.salesmanagement.logic.base.usecase.AbstractOrderPositionUc; -import java.util.Objects; - -import javax.annotation.security.RolesAllowed; -import javax.inject.Inject; -import javax.inject.Named; - -import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Implementation of {@link UcManageOrderPosition}. * @@ -36,6 +38,7 @@ */ @Named @UseCase +@Validated public class UcManageOrderPositionImpl extends AbstractOrderPositionUc implements UcManageOrderPosition { /** Logger instance. */ @@ -76,8 +79,8 @@ public OrderPositionEto createOrderPosition(OfferEto offer, OrderEto order, Stri // Save the order position and return it. getOrderPositionDao().save(orderPosition); - LOG.debug("The order position with id '" + orderPosition.getId() - + "' has been created. It's linked with order id '" + order.getId() + "' and offer id '" + offerId + "'."); + LOG.debug("The order position with id '" + orderPosition.getId() + "' has been created. It's linked with order id '" + + order.getId() + "' and offer id '" + offerId + "'."); return getBeanMapper().map(orderPosition, OrderPositionEto.class); } @@ -92,9 +95,14 @@ public OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition) { String action; if (orderPositionId == null) { action = "saved"; + Long offerId = orderPosition.getOfferId(); + OfferEto offer = this.offerManagement.findOffer(offerId); + Objects.requireNonNull(offer, "Offer@" + offerId); + orderPosition.setPrice(offer.getPrice()); + orderPosition.setOfferName(offer.getName()); } else { - OrderPositionEntity targetOrderPosition = getOrderPositionDao().find(orderPositionId); - verifyUpdate(targetOrderPosition, orderPosition); + OrderPositionEntity currentOrderPosition = getOrderPositionDao().find(orderPositionId); + verifyUpdate(currentOrderPosition, orderPosition); action = "updated"; } @@ -116,13 +124,31 @@ private void verifyUpdate(OrderPosition currentOrderPosition, OrderPosition upda if (!Objects.equals(currentOrderPosition.getOfferId(), currentOrderPosition.getOfferId())) { throw new IllegalPropertyChangeException(updateOrderPosition, "offerId"); } + if (!Objects.equals(currentOrderPosition.getPrice(), currentOrderPosition.getPrice())) { + throw new IllegalPropertyChangeException(updateOrderPosition, "price"); + } + if (!Objects.equals(currentOrderPosition.getOfferName(), currentOrderPosition.getOfferName())) { + throw new IllegalPropertyChangeException(updateOrderPosition, "offerName"); + } OrderPositionState currentState = currentOrderPosition.getState(); OrderPositionState newState = updateOrderPosition.getState(); - verifyStateChange(updateOrderPosition, currentState, newState); + ProductOrderState newDrinkState = updateOrderPosition.getDrinkState(); + + verifyOrderPositionStateChange(updateOrderPosition, currentState, newState); + + // TODO add verification methods of other sub-states of OrderPosition (i.e. Meal and SideDish) + verifyDrinkStateChange(updateOrderPosition, currentState, newState, newDrinkState); } - private void verifyStateChange(OrderPosition updateOrderPosition, OrderPositionState currentState, + /** + * Verifies if an update of the {@link OrderPositionState} is legal. + * + * @param updateOrderPosition the new {@link OrderPosition} to update to. + * @param currentState the old/current {@link OrderPositionState} of the {@link OrderPosition}. + * @param newState new {@link OrderPositionState} of the {@link OrderPosition} to be updated to. + */ + private void verifyOrderPositionStateChange(OrderPosition updateOrderPosition, OrderPositionState currentState, OrderPositionState newState) { switch (currentState) { @@ -154,6 +180,53 @@ private void verifyStateChange(OrderPosition updateOrderPosition, OrderPositionS LOG.error("Illegal state {}", currentState); break; } + + } + + /** + * Verifies if an update of the {@link DrinkState} is legal. This verification is based on both the states of + * {@link DrinkState} and {@link OrderPositionState}. + * + * @param updateOrderPosition the new {@link OrderPosition} to update to. + * @param currentState the old/current {@link OrderPositionState} of the {@link OrderPosition}. + * @param newState new {@link OrderPositionState} of the {@link OrderPosition} to be updated to. + * @param newDrinkState new {@link ProductOrderState} of the drink of the {@link OrderPosition} to be updated to. + */ + private void verifyDrinkStateChange(OrderPosition updateOrderPosition, OrderPositionState currentState, + OrderPositionState newState, ProductOrderState newDrinkState) { + + switch (currentState) { + case CANCELLED: + if ((newState != OrderPositionState.CANCELLED) && (newState != OrderPositionState.ORDERED)) { + throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState); + } + break; + case ORDERED: + if ((newState != OrderPositionState.ORDERED) && (newState != OrderPositionState.CANCELLED) + && (newState != OrderPositionState.PREPARED) && (newDrinkState != ProductOrderState.ORDERED) + && (newDrinkState != ProductOrderState.PREPARED)) { + throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState); + } + break; + case PREPARED: + // from here we can go to any other state (back to ORDERED in case that the kitchen has to rework) + break; + case DELIVERED: + if ((newState == OrderPositionState.PREPARED) || (newState == OrderPositionState.ORDERED) + || (newDrinkState == ProductOrderState.PREPARED) || (newDrinkState == ProductOrderState.ORDERED)) { + throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState); + } + break; + case PAYED: + if (newState != OrderPositionState.PAYED) { + throw new IllegalEntityStateException(updateOrderPosition, currentState, newDrinkState); + } + break; + default: + LOG.error("Illegal state {}", currentState); + break; + } + } /** @@ -173,4 +246,5 @@ public void setOfferManagement(Offermanagement offerManagement) { this.offerManagement = offerManagement; } + } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java similarity index 83% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java index 6939756a0..b82d9529b 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/service/impl/rest/SalesmanagementRestServiceImpl.java @@ -42,8 +42,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; -import org.springframework.transaction.annotation.Transactional; - /** * This class contains methods for handling REST calls for {@link Salesmanagement}. * @@ -53,19 +51,9 @@ @Named("SalesmanagementRestService") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) -@Transactional public class SalesmanagementRestServiceImpl { - private Salesmanagement salesManagement; - - /** - * @param salesManagement the salesManagement to be set - */ - @Inject - public void setSalesManagement(Salesmanagement salesManagement) { - - this.salesManagement = salesManagement; - } + private Salesmanagement salesmanagement; /** * Delegates to {@link UcFindOrder#findOrder}. @@ -75,9 +63,9 @@ public void setSalesManagement(Salesmanagement salesManagement) { */ @Path("/order/{orderId}") @GET - public OrderEto findOrder(@PathParam("orderId") Long orderId) { + public OrderEto findOrder(@PathParam("orderId") long orderId) { - return this.salesManagement.findOrder(orderId); + return this.salesmanagement.findOrder(orderId); } /** @@ -103,7 +91,7 @@ public PaginatedListTo findOrders(@Context UriInfo info) { criteria.setPagination(pagination); } - return this.salesManagement.findOrderCtos(criteria); + return this.salesmanagement.findOrderCtos(criteria); } /** @@ -116,7 +104,7 @@ public PaginatedListTo findOrders(@Context UriInfo info) { @POST public PaginatedListTo findOrdersByPost(OrderSearchCriteriaTo searchCriteriaTo) { - return this.salesManagement.findOrderCtos(searchCriteriaTo); + return this.salesmanagement.findOrderCtos(searchCriteriaTo); } /** @@ -135,7 +123,7 @@ public List findOrderPositions(@Context UriInfo info) { criteria.setCookId(parameters.get("cookId", Long.class, false)); criteria.setState(parameters.get("state", OrderPositionState.class, false)); criteria.setMealOrSideDish(parameters.get("mealOrSideDish", boolean.class, false)); - return this.salesManagement.findOrderPositions(criteria); + return this.salesmanagement.findOrderPositions(criteria); } /** @@ -148,7 +136,7 @@ public List findOrderPositions(@Context UriInfo info) { @Path("/order/{orderId}") @PUT @Deprecated - public OrderCto updateOrder(OrderCto order, @PathParam("orderId") Long orderId) { + public OrderCto updateOrder(OrderCto order, @PathParam("orderId") long orderId) { Objects.requireNonNull(order, "order"); OrderEto orderEto = order.getOrder(); @@ -159,7 +147,7 @@ public OrderCto updateOrder(OrderCto order, @PathParam("orderId") Long orderId) } else if (!jsonOrderId.equals(orderId)) { throw new BadRequestException("Order ID of URL does not match JSON payload!"); } - return this.salesManagement.saveOrder(order); + return this.salesmanagement.saveOrder(order); } /** @@ -172,7 +160,7 @@ public OrderCto updateOrder(OrderCto order, @PathParam("orderId") Long orderId) @POST public OrderCto saveOrder(OrderCto order) { - return this.salesManagement.saveOrder(order); + return this.salesmanagement.saveOrder(order); } /** @@ -183,9 +171,9 @@ public OrderCto saveOrder(OrderCto order) { */ @Path("/orderposition/{orderPositionId}") @GET - public OrderPositionEto findOrderPosition(@PathParam("orderPositionId") Long orderPositionId) { + public OrderPositionEto findOrderPosition(@PathParam("orderPositionId") long orderPositionId) { - return this.salesManagement.findOrderPosition(orderPositionId); + return this.salesmanagement.findOrderPosition(orderPositionId); } @@ -201,10 +189,10 @@ public OrderPositionEto findOrderPosition(@PathParam("orderPositionId") Long ord @Path("/order/{orderId}/position/{comment}") @POST @Deprecated - public OrderPositionEto createOrderPosition(OfferEto offer, @PathParam("orderId") Long orderId, + public OrderPositionEto createOrderPosition(OfferEto offer, @PathParam("orderId") long orderId, @PathParam("comment") String comment) { - return this.salesManagement.createOrderPosition(offer, findOrder(orderId), comment); + return this.salesmanagement.createOrderPosition(offer, findOrder(orderId), comment); } /** @@ -217,7 +205,7 @@ public OrderPositionEto createOrderPosition(OfferEto offer, @PathParam("orderId" @Path("/orderposition/") public OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition) { - return this.salesManagement.saveOrderPosition(orderPosition); + return this.salesmanagement.saveOrderPosition(orderPosition); } /** @@ -228,9 +216,9 @@ public OrderPositionEto saveOrderPosition(OrderPositionEto orderPosition) { */ @GET @Path("/bill/{billId}") - public BillCto findBill(@PathParam("billId") Long billId) { + public BillCto findBill(@PathParam("billId") long billId) { - return this.salesManagement.findBill(billId); + return this.salesmanagement.findBill(billId); } /** @@ -241,9 +229,9 @@ public BillCto findBill(@PathParam("billId") Long billId) { */ @POST @Path("/bill/{billId}/payment") - public PaymentStatus doPayment(@PathParam("billId") Long billId) { + public PaymentStatus doPayment(@PathParam("billId") long billId) { - return this.salesManagement.doPayment(findBill(billId).getBill()); + return this.salesmanagement.doPayment(findBill(billId).getBill()); } /** @@ -255,9 +243,9 @@ public PaymentStatus doPayment(@PathParam("billId") Long billId) { */ @Path("/bill/{billId}/payment") @POST - public PaymentStatus doPayment(@PathParam("billId") Long billId, PaymentData paymentData) { + public PaymentStatus doPayment(@PathParam("billId") long billId, PaymentData paymentData) { - return this.salesManagement.doPayment(findBill(billId).getBill(), paymentData); + return this.salesmanagement.doPayment(findBill(billId).getBill(), paymentData); } /** @@ -270,7 +258,7 @@ public PaymentStatus doPayment(@PathParam("billId") Long billId, PaymentData pay @Path("/bill/") public BillEto createBill(BillEto bill) { - return this.salesManagement.createBill(bill); + return this.salesmanagement.createBill(bill); } /** @@ -280,9 +268,9 @@ public BillEto createBill(BillEto bill) { */ @Path("/bill/{billId}") @DELETE - public void deleteBill(@PathParam("billId") Long billId) { + public void deleteBill(@PathParam("billId") long billId) { - this.salesManagement.deleteBill(billId); + this.salesmanagement.deleteBill(billId); } /** @@ -293,8 +281,20 @@ public void deleteBill(@PathParam("billId") Long billId) { */ @Path("/order/{orderId}") @POST - public void changeTable(@PathParam("orderId") Long orderId, long newTableId) { + public void changeTable(@PathParam("orderId") long orderId, long newTableId) { - this.salesManagement.changeTable(orderId, newTableId); + this.salesmanagement.changeTable(orderId, newTableId); } + + /** + * This method sets the field salesmanagement. + * + * @param salesmanagement the new value of the field salesmanagement + */ + @Inject + public void setSalesmanagement(Salesmanagement salesmanagement) { + + this.salesmanagement = salesmanagement; + } + } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/OrderPositionWebSocketController.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/OrderPositionWebSocketController.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/OrderPositionWebSocketController.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/OrderPositionWebSocketController.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java similarity index 87% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java index c830557b9..cc4a2d3ae 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/PositionStatusChangeTo.java @@ -10,6 +10,13 @@ public class PositionStatusChangeTo { private OrderPositionState status; + /** + * + * The constructor. + * + * @param id OrderId + * @param status OrderPositionState + */ @JsonCreator public PositionStatusChangeTo(@JsonProperty("id") Long id, @JsonProperty("status") OrderPositionState status) { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java similarity index 93% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java index 6f6204fcb..fd4a4aca7 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/salesmanagement/websocket/config/WebSocketConfig.java @@ -20,7 +20,7 @@ public void configureMessageBroker(MessageBrokerRegistry config) { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/positions").withSockJS(); + registry.addEndpoint("/websocket/positions").withSockJS(); } } \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/common/api/StaffMember.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/common/api/StaffMember.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/common/api/StaffMember.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/common/api/StaffMember.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java index ab09b6ee3..fe180dad9 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/StaffMemberEntity.java @@ -6,6 +6,7 @@ import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.Table; /** * The {@link io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity persistent entity} for @@ -13,7 +14,8 @@ * * @author loverbec */ -@Entity(name = "StaffMember") +@Entity +@Table(name = "StaffMember") public class StaffMemberEntity extends ApplicationPersistenceEntity implements StaffMember { private static final long serialVersionUID = 1L; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/dao/StaffMemberDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/dao/StaffMemberDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/dao/StaffMemberDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/api/dao/StaffMemberDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/impl/dao/StaffMemberDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/impl/dao/StaffMemberDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/impl/dao/StaffMemberDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/dataaccess/impl/dao/StaffMemberDaoImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/Staffmanagement.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/Staffmanagement.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/Staffmanagement.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/Staffmanagement.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java index 09612b5d1..425b81b6b 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberEto.java @@ -1,8 +1,8 @@ package io.oasp.gastronomy.restaurant.staffmanagement.logic.api.to; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Role; -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; import io.oasp.gastronomy.restaurant.staffmanagement.common.api.StaffMember; +import io.oasp.module.basic.common.api.to.AbstractEto; import java.util.Locale; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberSearchCriteriaTo.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/api/to/StaffMemberSearchCriteriaTo.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java index 10c913f9a..a82def485 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/logic/impl/StaffmanagementImpl.java @@ -18,6 +18,7 @@ import javax.annotation.security.RolesAllowed; import javax.inject.Inject; import javax.inject.Named; +import javax.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +31,7 @@ */ @Named @Component +@Transactional public class StaffmanagementImpl extends AbstractComponentFacade implements Staffmanagement, Usermanagement { /** Logger instance. */ diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java similarity index 80% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java index 04c93078f..ae7928ed8 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/staffmanagement/service/impl/rest/StaffmanagementRestServiceImpl.java @@ -19,8 +19,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import org.springframework.transaction.annotation.Transactional; - /** * This class contains methods for REST calls. Some URI structures may seem depricated, but in fact are not. See the * correspondent comments on top. @@ -31,18 +29,17 @@ @Named("StaffmanagementRestService") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) -@Transactional public class StaffmanagementRestServiceImpl { - private Staffmanagement staffManagement; + private Staffmanagement staffmanagement; /** * @param staffManagement the staffManagement to be set */ @Inject - public void setStaffManagement(Staffmanagement staffManagement) { + public void setStaffmanagement(Staffmanagement staffManagement) { - this.staffManagement = staffManagement; + this.staffmanagement = staffManagement; } /** @@ -54,7 +51,7 @@ public void setStaffManagement(Staffmanagement staffManagement) { @Deprecated public List getAllStaffMember() { - return this.staffManagement.findAllStaffMembers(); + return this.staffmanagement.findAllStaffMembers(); } /** @@ -65,7 +62,7 @@ public List getAllStaffMember() { @Path("/{login}") public StaffMemberEto getStaffMember(@PathParam("login") String login) { - return this.staffManagement.findStaffMemberByLogin(login); + return this.staffmanagement.findStaffMemberByLogin(login); } // although login is not explicitly needed here, the path structure is intentionally chosen @@ -79,7 +76,7 @@ public StaffMemberEto getStaffMember(@PathParam("login") String login) { @Deprecated public void updateStaffMember(StaffMemberEto staffMemberBo) { - this.staffManagement.saveStaffMember(staffMemberBo); + this.staffmanagement.saveStaffMember(staffMemberBo); } /** @@ -92,7 +89,7 @@ public void updateStaffMember(StaffMemberEto staffMemberBo) { @Path("/") public StaffMemberEto saveStaffMember(StaffMemberEto staffMemberEto) { - return this.staffManagement.saveStaffMember(staffMemberEto); + return this.staffmanagement.saveStaffMember(staffMemberEto); } /** @@ -102,11 +99,11 @@ public StaffMemberEto saveStaffMember(StaffMemberEto staffMemberEto) { @Path("/{login}") public void deleteStaffMember(@PathParam("login") String login) { - this.staffManagement.deleteStaffMemberByLogin(login); + this.staffmanagement.deleteStaffMemberByLogin(login); } /** - * Delegates to {@link UcFindStaffMember#findStaffMemberEtos}. + * Delegates to {@link Staffmanagement#findStaffMemberEtos}. * * @param searchCriteriaTo the pagination and search criteria to be used for finding staffmembers. * @return the {@link PaginatedListTo list} of matching {@link StaffMemberEto}s. @@ -115,6 +112,6 @@ public void deleteStaffMember(@PathParam("login") String login) { @POST public PaginatedListTo findStaffMembersByPost(StaffMemberSearchCriteriaTo searchCriteriaTo) { - return this.staffManagement.findStaffMemberEtos(searchCriteriaTo); + return this.staffmanagement.findStaffMemberEtos(searchCriteriaTo); } } diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/Table.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/Table.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/Table.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/Table.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/common/api/datatype/TableState.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java similarity index 98% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java index db07f6948..d27ced7af 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/TableEntity.java @@ -15,7 +15,7 @@ * * @author hohwille */ -@Entity(name = "Table") +@Entity // Table is a reserved word in SQL/RDBMS and can not be used as table name @javax.persistence.Table(name = "RestaurantTable") public class TableEntity extends ApplicationPersistenceEntity implements Table { diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/dao/TableDao.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/dao/TableDao.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/dao/TableDao.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/api/dao/TableDao.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java index 6560bcad7..825d9e916 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/dataaccess/impl/dao/TableDaoImpl.java @@ -6,8 +6,8 @@ import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.TableEntity; import io.oasp.gastronomy.restaurant.tablemanagement.dataaccess.api.dao.TableDao; import io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to.TableSearchCriteriaTo; -import io.oasp.module.jpa.common.api.to.OrderByTo; import io.oasp.module.jpa.common.api.to.OrderDirection; +import io.oasp.module.jpa.common.api.to.OrderByTo; import io.oasp.module.jpa.common.api.to.PaginatedListTo; import java.util.List; diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/Tablemanagement.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/Tablemanagement.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/Tablemanagement.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/Tablemanagement.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java similarity index 54% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java index bb0350390..3eea47487 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableEto.java @@ -1,107 +1,68 @@ -package io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to; - -import io.oasp.gastronomy.restaurant.general.common.api.to.AbstractEto; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.Table; -import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; - -import javax.validation.constraints.Max; - -/** - * {@link AbstractEto ETO} for {@link Table}. - * - * @author etomety - */ -public class TableEto extends AbstractEto implements Table { - - private static final long serialVersionUID = 1L; - - private Long waiterId; - - @Max(value = 1000) - private Long number; - - private TableState state; - - /** - * The constructor. - */ - public TableEto() { - - super(); - } - - @Override - public Long getNumber() { - - return this.number; - } - - @Override - public void setNumber(Long number) { - - this.number = number; - } - - @Override - public Long getWaiterId() { - - return this.waiterId; - } - - @Override - public void setWaiterId(Long waiterId) { - - this.waiterId = waiterId; - } - - @Override - public TableState getState() { - - return this.state; - } - - @Override - public void setState(TableState state) { - - this.state = state; - } - - @Override - public int hashCode() { - - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((this.state == null) ? 0 : this.state.hashCode()); - result = prime * result + ((this.waiterId == null) ? 0 : this.waiterId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - if (!super.equals(obj)) { - return false; - } - TableEto other = (TableEto) obj; - if (this.state != other.state) { - return false; - } - if (this.waiterId == null) { - if (other.waiterId != null) { - return false; - } - } else if (!this.waiterId.equals(other.waiterId)) { - return false; - } - return true; - } -} +package io.oasp.gastronomy.restaurant.tablemanagement.logic.api.to; + +import io.oasp.gastronomy.restaurant.tablemanagement.common.api.Table; +import io.oasp.gastronomy.restaurant.tablemanagement.common.api.datatype.TableState; +import io.oasp.module.basic.common.api.to.AbstractEto; + +import javax.validation.constraints.Max; + +/** + * {@link AbstractEto ETO} for {@link Table}. + * + * @author etomety + */ +public class TableEto extends AbstractEto implements Table { + + private static final long serialVersionUID = 1L; + + private Long waiterId; + + @Max(value = 1000) + private Long number; + + private TableState state; + + /** + * The constructor. + */ + public TableEto() { + + super(); + } + + @Override + public Long getNumber() { + + return this.number; + } + + @Override + public void setNumber(Long number) { + + this.number = number; + } + + @Override + public Long getWaiterId() { + + return this.waiterId; + } + + @Override + public void setWaiterId(Long waiterId) { + + this.waiterId = waiterId; + } + + @Override + public TableState getState() { + + return this.state; + } + + @Override + public void setState(TableState state) { + + this.state = state; + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableSearchCriteriaTo.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableSearchCriteriaTo.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableSearchCriteriaTo.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/api/to/TableSearchCriteriaTo.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java similarity index 95% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java index 027b79697..529912a03 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/logic/impl/TablemanagementImpl.java @@ -22,6 +22,7 @@ import javax.annotation.security.RolesAllowed; import javax.inject.Inject; import javax.inject.Named; +import javax.transaction.Transactional; import javax.validation.Valid; import org.slf4j.Logger; @@ -33,6 +34,7 @@ * @author etomety */ @Named +@Transactional public class TablemanagementImpl extends AbstractComponentFacade implements Tablemanagement { /** Logger instance. */ @@ -41,7 +43,7 @@ public class TablemanagementImpl extends AbstractComponentFacade implements Tabl /** @see #getTableDao() */ private TableDao tableDao; - private Salesmanagement salesManagement; + private Salesmanagement salesmanagement; private Staffmanagement staffmanagement; @@ -137,7 +139,7 @@ public boolean isTableReleasable(TableEto table) { if (table.getState() != TableState.OCCUPIED) { return true; } - OrderEto order = this.salesManagement.findOpenOrderForTable(table.getId()); + OrderEto order = this.salesmanagement.findOpenOrderForTable(table.getId()); // no open order so the table is actually free... return order == null; } @@ -165,9 +167,9 @@ public void setTableDao(TableDao tableDao) { * @param salesManagement new value for salesManagement */ @Inject - public void setSalesManagement(Salesmanagement salesManagement) { + public void setSalesmanagement(Salesmanagement salesManagement) { - this.salesManagement = salesManagement; + this.salesmanagement = salesManagement; } /** diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/api/ws/v1_0/TablemanagmentWebService.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/api/ws/v1_0/TablemanagmentWebService.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/api/ws/v1_0/TablemanagmentWebService.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/api/ws/v1_0/TablemanagmentWebService.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java similarity index 94% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java index 645c85c44..f05a97620 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/rest/TablemanagementRestServiceImpl.java @@ -23,8 +23,6 @@ import net.sf.mmm.util.exception.api.ObjectNotFoundUserException; -import org.springframework.transaction.annotation.Transactional; - /** * The service class for REST calls in order to execute the methods in {@link Tablemanagement}. * @@ -34,7 +32,6 @@ @Named("TablemanagementRestService") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) -@Transactional public class TablemanagementRestServiceImpl { private Tablemanagement tableManagement; @@ -60,7 +57,7 @@ public void setTableManagement(Tablemanagement tableManagement) { @Path("/table/{id}/") public TableEto getTable(@PathParam("id") String id) { - Long idAsLong; + long idAsLong; if (id == null) { throw new BadRequestException("missing id"); } @@ -122,7 +119,7 @@ public TableEto saveTable(TableEto table) { */ @DELETE @Path("/table/{id}/") - public void deleteTable(@PathParam("id") Long id) { + public void deleteTable(@PathParam("id") long id) { this.tableManagement.deleteTable(id); } @@ -149,7 +146,7 @@ public List getFreeTables() { */ @GET @Path("/table/{id}/istablereleasable/") - public boolean isTableReleasable(@PathParam("id") Long id) { + public boolean isTableReleasable(@PathParam("id") long id) { TableEto table = this.tableManagement.findTable(id); if (table == null) { @@ -160,7 +157,7 @@ public boolean isTableReleasable(@PathParam("id") Long id) { } /** - * Delegates to {@link UcFindTable#findTableEtos}. + * Delegates to {@link Tablemanagement#findTableEtos}. * * @param searchCriteriaTo the pagination and search criteria to be used for finding tables. * @return the {@link PaginatedListTo list} of matching {@link TableEto}s. diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/ws/v1_0/TablemanagementWebServiceImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/ws/v1_0/TablemanagementWebServiceImpl.java similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/ws/v1_0/TablemanagementWebServiceImpl.java rename to samples/core/src/main/java/io/oasp/gastronomy/restaurant/tablemanagement/service/impl/ws/v1_0/TablemanagementWebServiceImpl.java diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/META-INF/cxf/org.apache.cxf.Logger b/samples/core/src/main/resources/META-INF/cxf/org.apache.cxf.Logger similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/META-INF/cxf/org.apache.cxf.Logger rename to samples/core/src/main/resources/META-INF/cxf/org.apache.cxf.Logger diff --git a/samples/core/src/main/resources/META-INF/orm.xml b/samples/core/src/main/resources/META-INF/orm.xml new file mode 100644 index 000000000..e18840ef7 --- /dev/null +++ b/samples/core/src/main/resources/META-INF/orm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/core/src/main/resources/application.properties b/samples/core/src/main/resources/application.properties new file mode 100644 index 000000000..097c5687a --- /dev/null +++ b/samples/core/src/main/resources/application.properties @@ -0,0 +1,20 @@ +# This is the configuration file shipped with the application that contains reasonable defaults. +# Environment specific configurations are configured in config/application.properties. +# If you are running in a servlet container you may add this to lib/config/application.properties in case you do not +# want to touch the WAR file. + +#server.port=8080 +spring.profiles.active=h2mem +spring.application.name=restaurant +#server.context-path=/ + +security.expose.error.details=false +security.cors.enabled=false +spring.jpa.hibernate.ddl-auto=validate +#http://stackoverflow.com/questions/25283198/spring-boot-jpa-column-name-annotation-ignored +spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy + +# to prevent that Spring Boot launches batch jobs on startup +# might otherwise lead to errors if job parameters are needed (or lead to unwanted modifications and longer startup times) +# see http://stackoverflow.com/questions/22318907/how-to-stop-spring-batch-scheduled-jobs-from-running-at-first-time-when-executin +spring.batch.job.enabled=false diff --git a/samples/core/src/main/resources/config/app/batch/beans-billexport.xml b/samples/core/src/main/resources/config/app/batch/beans-billexport.xml new file mode 100644 index 000000000..103097efd --- /dev/null +++ b/samples/core/src/main/resources/config/app/batch/beans-billexport.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/core/src/main/resources/config/app/batch/beans-productimport.xml b/samples/core/src/main/resources/config/app/batch/beans-productimport.xml new file mode 100644 index 000000000..fd316c8c0 --- /dev/null +++ b/samples/core/src/main/resources/config/app/batch/beans-productimport.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/dozer-mapping.xml b/samples/core/src/main/resources/config/app/common/dozer-mapping.xml similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/dozer-mapping.xml rename to samples/core/src/main/resources/config/app/common/dozer-mapping.xml index f806f2518..2d564f2e6 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/common/dozer-mapping.xml +++ b/samples/core/src/main/resources/config/app/common/dozer-mapping.xml @@ -44,8 +44,8 @@ serialization. --> io.oasp.gastronomy.restaurant.general.dataaccess.api.ApplicationPersistenceEntity - net.sf.mmm.util.transferobject.api.EntityTo - + io.oasp.module.basic.common.api.to.AbstractEto + this persistentEntity diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/gui/dispatcher-servlet.xml b/samples/core/src/main/resources/config/app/gui/dispatcher-servlet.xml similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/gui/dispatcher-servlet.xml rename to samples/core/src/main/resources/config/app/gui/dispatcher-servlet.xml diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/access-control-schema.xml b/samples/core/src/main/resources/config/app/security/access-control-schema.xml similarity index 100% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/security/access-control-schema.xml rename to samples/core/src/main/resources/config/app/security/access-control-schema.xml diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/websocket/websocket-context.xml b/samples/core/src/main/resources/config/app/websocket/websocket-context.xml similarity index 96% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/websocket/websocket-context.xml rename to samples/core/src/main/resources/config/app/websocket/websocket-context.xml index 011b3d1b4..c4d0a303c 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/config/app/websocket/websocket-context.xml +++ b/samples/core/src/main/resources/config/app/websocket/websocket-context.xml @@ -1,9 +1,9 @@ - - - - - - \ No newline at end of file + + + + + + diff --git a/samples/core/src/main/resources/config/application-h2file.properties b/samples/core/src/main/resources/config/application-h2file.properties new file mode 100644 index 000000000..8f76ea65c --- /dev/null +++ b/samples/core/src/main/resources/config/application-h2file.properties @@ -0,0 +1,8 @@ +# Datasource for accessing the database +spring.jpa.database=h2 +spring.datasource.url=jdbc:h2:./.restaurant; +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.datasource.username=sa +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver +flyway.locations=classpath:db/migration,classpath:db/migration/h2 \ No newline at end of file diff --git a/samples/core/src/main/resources/config/application-h2mem.properties b/samples/core/src/main/resources/config/application-h2mem.properties new file mode 100644 index 000000000..08ca6ff52 --- /dev/null +++ b/samples/core/src/main/resources/config/application-h2mem.properties @@ -0,0 +1,8 @@ +# Datasource for accessing the database +spring.jpa.database=h2 +spring.datasource.url=jdbc:h2:mem:app; +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.datasource.username=sa +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver +flyway.locations=classpath:db/migration,classpath:db/migration/h2 \ No newline at end of file diff --git a/samples/core/src/main/resources/config/application.properties b/samples/core/src/main/resources/config/application.properties new file mode 100644 index 000000000..3173fc9f8 --- /dev/null +++ b/samples/core/src/main/resources/config/application.properties @@ -0,0 +1,22 @@ +# This is the spring boot configuration file for development. It will not be included into the application. +# In order to set specific configurations in a regular installed environment create an according file +# config/application.properties in the server. If you are deploying the application to a servlet container as untouched +# WAR file you can locate this config folder in ${CATALINA_BASE}/lib. If you want to deploy multiple applications to +# the same container (not recommended by default) you need to ensure the WARs are extracted in webapps folder and locate +# the config folder inside the WEB-INF/classes folder of the webapplication. + +server.port=8081 +server.context-path=/oasp4j-sample-server + +http.mappers.jsonPrettyPrint=true +security.basic.enabled=false + +# Flyway for Database Setup and Migrations +flyway.enabled=true +flyway.clean-on-validation-error=true + +# updates schema if existing schema is not complete +# (used in training for adding datatypes without updating schema-migration-scripts) +spring.jpa.hibernate.ddl-auto = update + + diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0002__Master_data.sql b/samples/core/src/main/resources/db/migration/V0002__R001_Master_data.sql similarity index 67% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0002__Master_data.sql rename to samples/core/src/main/resources/db/migration/V0002__R001_Master_data.sql index 11c76c20a..e00a65ad4 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0002__Master_data.sql +++ b/samples/core/src/main/resources/db/migration/V0002__R001_Master_data.sql @@ -19,19 +19,19 @@ INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VAL INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (11, 1, 'Drink', 'Bier', false); INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (12, 1, 'Drink', 'Wein / Apfelwein', false); -INSERT INTO OFFER (id, modificationCounter, description, state, meal_id, sidedish_id, drink_id, price) VALUES (1, 1, 'Schnitzel-Menü', 0, 1, 5, 10, 6.99); -INSERT INTO OFFER (id, modificationCounter, description, state, meal_id, sidedish_id, drink_id, price) VALUES (2, 1, 'Goulasch-Menü', 0, 2, 6, 11, 7.99); -INSERT INTO OFFER (id, modificationCounter, description, state, meal_id, sidedish_id, drink_id, price) VALUES (3, 1, 'Pfifferlinge-Menü', 0, 3, 8, 12, 8.99); -INSERT INTO OFFER (id, modificationCounter, description, state, meal_id, sidedish_id, drink_id, price) VALUES (4, 1, 'Salat-Menü', 0, 4, 7, 9, 5.99); -INSERT INTO OFFER (id, modificationCounter, description, state, meal_id, sidedish_id, drink_id, price) VALUES (5, 1, 'Cola', 0, null, null, 10, 1.20); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (1, 1, 'Schnitzel-Menü', 'Description of Schnitzel-Menü', 0, 1, 5, 10, 6.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (2, 1, 'Goulasch-Menü', 'Description of Goulasch-Menü', 0, 2, 6, 11, 7.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (3, 1, 'Pfifferlinge-Menü', 'Description of Pfifferlinge-Menü', 0, 3, 8, 12, 8.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (4, 1, 'Salat-Menü', 'Description of Salat-Menü', 0, 4, 7, 9, 5.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (5, 1, 'Cola', 'Description of Salat-Menü', 0, null, null, 10, 1.20); INSERT INTO RESTAURANTORDER (id, modificationCounter, table_id, state) VALUES (1, 1, 101, 1); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, order_id, price) VALUES (1, 1, 1, 'Schnitzel-Menü', 'mit Ketschup', 2, 1, 6.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, order_id, price) VALUES (2, 1, 2, 'Goulasch-Menü', '', 2, 1, 7.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, order_id, price) VALUES (3, 1, 3, 'Pfifferlinge-Menü','', 2, 1, 8.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, order_id, price) VALUES (4, 1, 4, 'Salat-Menü', '', 2, 1, 5.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, order_id, price) VALUES (5, 1, 5, 'Cola', '', 2, 1, 5.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (1, 1, 1, 'Schnitzel-Menü', 'mit Ketschup', 2, 2, 1, 6.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (2, 1, 2, 'Goulasch-Menü', '', 2, 2, 1, 7.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (3, 1, 3, 'Pfifferlinge-Menü','', 2, 2, 1, 8.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (4, 1, 4, 'Salat-Menü', '', 2, 2, 1, 5.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (5, 1, 5, 'Cola', '', 2, 2, 1, 5.99); INSERT INTO BILL (id, modificationCounter, payed, total, tip) VALUES (1, 1, true, 14.98, 1.3); INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,1); diff --git a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0003__Add_blob_table_and_data.sql b/samples/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql similarity index 99% rename from oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0003__Add_blob_table_and_data.sql rename to samples/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql index c2106cf82..a070e18a1 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/main/resources/db/migration/V0003__Add_blob_table_and_data.sql +++ b/samples/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql @@ -1,14 +1,2 @@ -ALTER TABLE PUBLIC.PRODUCT ADD PICTUREID BIGINT; -UPDATE PRODUCT set PICTUREID=10; - -CREATE TABLE PUBLIC.BINARYOBJECT ( - ID BIGINT NOT NULL, - MODIFICATIONCOUNTER INTEGER NOT NULL, - DATA BLOB(2147483647), - SIZE BIGINT NOT NULL, - MIMETYPE VARCHAR(255), - PRIMARY KEY (ID) -); INSERT INTO BINARYOBJECT(ID, MODIFICATIONCOUNTER, SIZE, DATA, MIMETYPE) VALUES (10, 0, 72861 ,'89504e470d0a1a0a0000000d49484452000000c8000000c81006000000fdc872dd0000800049444154789cec5d077c5545d69ffb92d04297d8404db020c15e028a9817052c5850888b65dd447445d85d753fb16b6eec8a5d41455c13171509764511352f7614ac80080a449a0816a4a4e77e73dffccfbc37e7bec90b5d77f7ee6f3d9c977bcf3d77e6cc9c32e7cca48aff5d9b731d618174f552c00114f9cda4db8bc16d754d6ee67d7314f0ca4c9cff3d00e76e2a63ffbbb6e945726a9343926b7e5fb2eb8ccde26ae32f2e7fc92ec8b3677b8eff5eb6a98cfda75cff5320cdbbc280ae024e1ef0df003b00ee88bf17b3e7803b4e92f7d0c0a48976de46f2b9b9d7b30a786e92fba6e0be29e6cf5e2efe41fcaf06fc1a10dfef95031fc9eeffdfb56d2f57012daf7451bf91bc925c5700477f3ad4afc39a7e8d83f78803369ec5cdba52009b29d7de7e0a3ac9e49afecec6b357847f2479cfffaeffd42b0c185180267c0d31d042c04310cc140ca054086cea4d0aa6a501deac608b1680b798b0654bc083016f05fc50c156adb60e24fafa7dc7317e5a327ecfc6f7bc0f38c0fc5efafe941b01430a866e50902620872bd4086058fcefda1a571830a280966718425aae8f5190fa8dfa3120d7e8779283160301494e3e5050cb11c9d5ef55ae312e699cd2b8b5c935c97340aea93d49ae5dc0b0f80fbdfedb3d9030a0ab80f62c4820e83e36e139c702920091e52205eec4d20b96b56923c49ec507cedae502299cff6a35a0ad540ca9d35aeedaee2d298453437f4e4f9737f7747af802e81ded558b1931961c57fecfe76b77d128241daf44acf7ffeefc2caec02d51e8fcec98f815c0afc07da728dc29717e32bef97871a46f29354ca83b61fd7542d416d7fcb6f63221aa2f5c377eddde427cfedadb137eb84b88f7d6bcd0a3bab77ac4c38012cf032708cbcc7b0f1003cef300df357141f7870129a451c1a063d2d70ae67f57f3aeb0020e6f573ed145f03b148743f046f3795fae8767de7a48468610ed4eeadca5f34572926ddde2fc761ba45ca7a535b693cf39f3424b5bc909dba9768ac4c742349ed47843546ed738a3a3445a8a1ba372bd9b926bb1935807b96f9e3c0bc8b31e07cee5d1fffea4f0c6eac6f7ebea84a8ffb276e9ba57a45c2fa89ebd6e9d10bfcdfbf9e835ff924ec8b47bc6af947cff72daca168d6f290a24d75a6e49de489e09f6078422d1f24d3064b62f89bb9e40e8776a6f1790f03fec952ca4f29f7665039242a009cc054e03260218e781b4bfa24b17e71d212e587ddbb85e6542b46dd3b9e4d46952213c99b2c721df4a6ba45de8f283baca7bf70a3dd8ed1ce10fca637c0523d54104ef54c336ac70e9d62b3c0ff85c312a8af7528101f96b187f575c8515ee54e86941e111e079b83fac70799f8bbb8a814780e7a9f703cf1379461b79725c1c2dc11d8d5d974c9403b35363ff05e3e5803cacbacb872f09b17cf477e35fbe5d8847ca479ffacd3772c05e52bbccbb5e3dda08179e42548dd79b38b9f88d6f037f1010fdc207a61e6080ff5328962bac80291971bf931cbb0c9713ffa90ffcada1cd1d52ec86f46dd7f74839cfaf6bd3ed4cd9dfa195a18b7bf490f08ed08bfb3c296fbed2f9a5c3bdd17714c7539352a4702e7f2ef062c24d794b302e5c3c077a5c7e03f21dc1572a7a118b3cd3f59e1853552565af5bc3830b779306d47d0d5fce7f5488758dbffee5f97f08f1e592770ade950ae3c5cc07effdf967f5889647926bc8ad96732ecf24e7d7b3e7c38024bfae79ff1f57a1fcb72890b0027a8061f1cf41ac375e6174fba5c7d490b49ccf9973dd5b474b0bbde5fa36a9674b8590727ecab24172a089279d3332e6c64dd0d910f0af930834298e0a61d87ff2bfa448e6021f053cb1e220dc351587c68bf1b5f9186853028ac4059fc5e0d3051d1e096ff2f2def5fef2a3b4e86a8baac3af1f21c4ea51cb9e9afc8c100f3ef08fbf7c78bc1035876c98d0d04fddab0718065603299ca1803fe0ef3400b985470ac535effbe30ebc2d746111376008f1d0ab84e7ae2aceedd041883dceec396cc810e9391cd562c8b07952417c18fab4ef1bf2a6a39c375adc6a18244a1e36da7031479be32491b78d378c22b82b0fb8499f29ae665fbee124e5b2e1a086215f49b9ac9eb86eda0bd2d39efbf6870ba64c11e2e9cadbce5abab7ba953c98c646402886c6a31524b9df648512de28ceb7e3f59fae40220ae8d014b227686085fe2ec45f6a6e0c771c2c3deb8f7a9c34525ac2a97f4d7bfcfce1f29e5d9cfebb2d147605908d097f0ad4d128780e6e12cfc1a600ca809fc13c94e2c080c157255554a3807f0d3c8caf570331b987b34957e3418d177d5f2ac4fa9fd69cf2c47942bc7ec0e315fffa8b101ff678e9a33558e3696800dc17cf9c0e9c069acdb223c807de7fcbe26518d055c01907488610290c2909a3cb4a2e3df06221da7cd5eefacb5e91b2fe51ca8cc1f7c83f5ee3bcde6a4693868c033c0cbc690fd8c5046ef3b08b418f8d8b0413bda2175030f04c2a347d07385a63ebcab39c4322bea2a89f5a7bd4fba942ac1ab674b7717244dd79eef997bd592f656f60e3cb0d4ca1d41f059c0ca5a34dc83d1aae58fe381e77687b33b085afb0027cd19bf4a4bfe670f6e1d7f56ebf548ea369cf7c75538a1099a7f55af7dd04e96134a6762ff645746771acaf38bcb0a7a81509356d45142e3b55e1655ed47e96ff2dc3dfa3dd2def8a44f172747f44e15e2ec3c3c0cb81e78b223ca7dee32a5c3e17c6730af78097030f6bbe8a0c3e87629a21be72357de253e1459aaf22834f21c81edaa82bf479e8a1dda5c268b7a4d309d74a4531f4c54bbb7e768a103764bc10bee66a21fafe6df01d3b22aba7e58b0aa66111360db1e894774d18a2c5784c0521f295220ae829e23f35add25540875809fe4941bf5d464f2e2dcdb95c88ebcf9cf2f68b2f08913ebb43c3cc41f29e502832cc4ff2a815aff98a2320c7246f618d73f950d35b4cfe144ef2e7327a11462fc2e811fd987c937f69c833d10ff01b93e748b3f8cdd5fc6e923cfb8ac897bfd43b5aa4f6930a629743baaf78ba8710b7674f7bf46de9698c4effd7d7a79e2adbf9aa50eb5658b40f2ccad3623cc937d65242b496fa0e2019ba11e0866afd3d5e29db9b812d74b90a38a50ccf5230243be8f2034abf3be61821323eef5659faaafc2d2b74f219afc93f9e25766b3922cea2c914a6055608fda32d1ae0b94ed4c2971e880a20643825782e338ae7295c3e95a99e032e804780e70177912c59a83c1a892beeb3c88557b87c2a8ce7b2705f18f765197c4e15e90a075f64c1656a3e155ea8f9cc637c9a1e0ed1dfc8cb0939bd5b494fa345bf56e123a402d9f7829cefcf7c5888bd871dd2ed2b69817d32e1f52f9677c5bde729187a023838d1592d05c023c02bd9cb5e05244552b2291cff8eae88024e21c3e5771714dcf846875a214e9a72d1f0b1b365fbd6b5aabfbfb3fcdbbad0ebfb3c1dbd2d4fca52bc45afa8c42c7a856792e50fb9ce0bc8877a2bc94725f04cbd96a1e86731fa25c00b40af447b382506bde41eb5c96f4c9e33151f49f8ad60fc4634bf345d6fd2159a93b27aa72ba4a1744ca7f5833b0a71ccddc3e6f6a91662e6fd6fe4bdb45688ea97d77f010e63f28c7ea47989feee3039760ad8cbe8ef2e60647338df92d71f5d814414e0032c24f11da675ede47b1c173ff2f0928b074b2be08456a32748d7d2e928fe6ff7cb842f8833a3cf6eac2b4c782926d47c087819043c4f2f062a3c4baf4144713900159e093c160250cf459c3151bc10d3656c00293c532f5e2abc50d32f009f0acf56d92ff22b2fc7f7d173cde3b3c49c789c32e0bd366fe039739dddda48cbb8d3693bfd69b0f4040fab1d78defa3942bc77d0f3fd67af97377c2c9ed116363c0fddbf61e018507aea590c380ab084c1c50cfedeaf8802da838e33844666dc5bbb4b8d103bdd97b5f76bf2efa191a15927f83ded4849f27b46cb99368894a14172ed3043a3848552638ac48de25a3eb421a30cac126d6099f42a809362aa04bd4c162a73f8b8b018709c5f32e0285416534c8c5f2ecfa6e1a5e955f2e97bd3ae94dcd4637797be50dff5831f3bbe95103b7f9ab9fc0be9617f59f5ce0d3f7f2af0c980590c87bc9342d10a02bf7b7fc17d6c9edbfe06d21f2d84155620517dc60e27ef7a89ef1a5ef1d8c49b2f9396e8888abbf3abe4d499724beadb779e246fbac2dba7e521712e385c5dc2c9d5952eb4f1bbf5be6c06c3faef70d1f573b98c4eae41c705de53d309b3f787d9fbc38ccf30a3aff0fc24df97cb20bdcf765fbeca95dadc10175dcefdcefc96b709d165c7aeab6e7c4f88bb9e29fff3a27385b83a34b174947c93b3a7f36afa27eade361f2bd8fa76055ba2ce200da18254d425a4a0f092425d8101ea6e0ec75bf17215e072ed7fc788fbef7978974764bbbc30e9dee9470ad1f9c25d5f583a51fe7181d3eb9056861c303913a69c858173b9e6fd6c9563848838bddc24e3c43ebe368d5f3bff4d8fbb00bf0cdfd41017bb52d3d21ecc96f27bf0b5c7be37ed2a21ee5835fd377fede4ac4bafbee4f057d43de92a36a0e5bad5f10a527d4a1ae45b87bc28bd9a0c0a2627342f6efbeb8fe2818415d01341448190b43d8e4a39addc8f399ed6f9921f1f9d2f3fa943eac4ffbb2cfae7f342c3e35cd60258f8e3d00d8360afc203901e45a67a9776b9159ec742539570c15d71a2a2a7435cf9e0d1e8d69845c72c38edf910ae426222839e33435c01d7ddc6a70bbc58d5b54b5c2df2f31017b71423c00b359f59069fd92a24e6ccdcb2212e7df51367a7ec2907d5c0f61d730b8438b2f4d495bb5c29c4274fbdfef67b7200d6fd5253438b8f3a04e0022a0e847707f0b180e094f2ef7588b3c07c6ebb5d78bfe6ab44015faeff71cfc3693d2609d16179467ab954acce0fcee107f96b46310f7843f4e67c27fab53a6444728610a8bc2f0ceaa62762f5b059c888cbb14d3e329907efe8f45d176f2f34e8337e93876c897e9210977ddc317e81f390dc9692675ca12f535674bc54885dd6779f709a84596fedf7ca37c3849875f3f44796eca5eed11e495e621a7c319df2ceb45c43b1e89e5ebc25386fcef57b5720a80f50c12661288ed39ebbf895f4b652d31fd3bfdbe4d6f2b70ea1be43fd18b86dad8026e8b0521c7a82aeb4645971973b8fc5564b31e0b2a13866824b5b6880b2aef400c18020d73d177caeb684b8f800d4316c169a2ad4aebc7aae1821311ee2c2341a17232f60f44dbc140561f92a241608716da1d8325d2d3f69dd61bf9385e833e1a4437b7e24c4d7bd679c551e1162dda45f9e6df8b3ba470f38c569ac9e84f6682a31a107c84362db3cb4e5323e4a14f0e5fad2d327bc947385b4521f68b7ea8db3e48f473b3bef72b508aea5e5a2ff660a55c6aa0d01c859a596b3e8dba49c15a8fbb4bc642a26f85a1d8d8766cbb1a25702fab15092a25fcce8050c17d02b64e322a6984c7ef39284e42a412fb399fc16b0905c1e70572bae4ab1052ea79d33d0af70ef727ad76306ad1262dff29c65cba5c73163c2ab777efb286e2295b5185071a04358f4bb561c61866f7345f27b5720aaeb759ebbefb2f51f77eeedad4608b1ffcbfd4e7db1a3ff5be8bd81fea2a17d714de13958a476510f5d29da466120b64a038759302e048b2cba7c65014a8f661470d0c180cc648be585164f42683cead1480f643ff01dc673598c4f12b330eecb32f80c93258745fe584cb8047f570ab0447b380a77816769854a7c293c171ecd4c78343cb6be9562cb69b35aeeb0e7b1421cb25fffcbf6972a7ad67dd3fff646ad1035376fa8e079f35e4fe087038f002f31e1761b706410d15e4ae0c3571c97ecf6e88043d709d1eaa3f475d3fbca1fab9db69d3a095feec860898057c255126f3e0ca29842cf54f7b1fe136cb1991b44b1fa8a02e08a5e72392683cba45fa80db002f57ae6f1307ee3e42fb3297e35bda007a5e871c32819bf31c55a01fa61f06fd2afd49e378dbf4dbbfa8973fcecab8e13339e1d203deb1ee71cbe6ed92d5291944f5dbe00c9247c2d84d27ff9da87a738b57b245bfdfabd2a90b0023a0b474e1cfb1edafbdad41be53c76ceb09d9e901de0fc14aa3ce96f22e83904f3da155e06415985e18bd08ef624b82b6fb7e894a04d45b7e5a28069a61660d322b765bf04b355c6814f2a2474f11d8a6f872d9697989e439ca7021c218e6215e210b49858c13c9cd8402b34db8185e22a40cf926da62dce2c66d1966c999040daf72d4ede437272e84e037aef2e3d9077339f7bcc27ecbdd158aff3ea115bf6bae0a102e02ef00860097e07becd1409d56d60b1df571ca3fefce02b7b2f971e47dbf69f4cf73d8dd9cec79d4e8ff3282bd9623059e6b92ca4c843300ef3ac2bf5c4e9aafb40dfd1868732902a028686a2c72bc8b35808a9c44cce207e831e8e85dfc266f2cb43ca4e52c388f31b01bf0a2f481c0a0ef0bba543b65231fba1ab8e6376bc3b4f52ec76fc3e977ebdb3109fcd7beb8325efe29eb002dee326d4f24b38c1c59ab671dfd65b6cffbd2990b0023a0b679582a1ef653fef78f3fa3183e4bfbd50bff3a422117031a547607a0e3aeb435be80a1f8461ebaab45ba778e3d26c039e43bef268e4b49f0b5c790e2c7416c767624f2253e36afacb09585ec4679ec1676c002abcd0f41c4891c8e7f603fd30be2fa1e7104b070e588a0a2f08649b450c3e93a74f46f0f6cd1a782d17b45edf437aa087b43bf6afad3e948ae4e5e71efd4405e9627b735d04e89abfeb104026231a062c002cd91c0e135ca0ef4c0594beef79336fbdc9df5baad3e89d2e8ff80af06ef17ad737a3f2a3dac7b69641064c2926eafcc45973564320e0b1b290514c91287ac90d0d538e89bec3c69f13480736e83797dfb82c3193dec61a46997cbe08648935c9ef160bd91e2d3d923da55df641d773fa4b8fa4edba0e377c749b105fd7ccb861f549ea16ed81907cbbc00b184e8a2413300258c2e016bb7e6f0aa444010a7e84e440bbe41f8fb61a72bd64759fb49bfd6caae8c4e78b5465920a59be15020dc4626ed1359dbe1ab7c80e41043e1591ec5c65bf4a2f4929289e665b6949b3e5ae760ed26e2348bbddc834dbc000c947086baa9e284ad47396e48042aba5081c21c01c786e1116e2d3138f9e8e1ddc17c67d0ebe07f8e685b8dad4b49f7ec8fdd2723b719f31f3a649cbedf5b71eada401471e090d382a557381534cb988118d009630b899974e3b960651b7a77bec9422278a9cc8a04e9356c81f478bb2c3e78a449eafe2b632b0369519c57361c0d8428a3c64c4d70688be635bfb4abc961833882c86464c3131fa01f9d8347e631e2fc68596bf84fc26358c821e8e8bfb0a9be4770b876c9dfd9d65fe1ac9ae1bf67ce3882b855878d897535e953eff2f7356de545d8d9b10b2f588a3087092ef45c04b80937c9702d2738b3787d3f8ebf7a2405c05e20b6d865f7d5bddce774bd7fe938e4fbdee87ac16887e7e419ad5c58c854c144e9e0362ab729a3f11ef52825c8a8167cbce2041a9b4780ed9ba9010d95316cf2116c3263ef3189f0a2fc3692083f404adde53c806888d4f3e00a712df1b991c602bec2a80c22b43b2c0c62eaab2ba15f9dc68d0d9b463861c650b7629df7555df3a217ed87571e3cbd2725bb9b872ce06b5ba151b5805c049a1ec81df6940d2df29df3e0f7fa7cd37576d128746e19f7ff99ef4f9d78c993c7aacfcf7e9a13347dc16e74904e5577141f25bca4230a5f8aa0cd433e9898dd1b37bd6444fd18f6d1552095cd1b31b44267dbe56e268f9a9041e06fd0ab48949df05fd2c6d6025e437e6f1327a317e2b8cf6284cc22f85fa2c1e9495df606859d1ab741cb1195768ef942eed2f16a2e7b23ec7ecd1284568ce336ba6d7abbfe92d7b4a80ff85c14cfc7d3120c97744c12dbf36b2bd154858019dc61851c0df3a205c3dec9f974b8d1aaa09650cf0b7baa0892e3621bba0014bc1e262566a4f42ad3114e318a3b0ca4ed2169760829167f11c08d769948a9e54001be29fb3c7b0399f68854158944f163a13cd5c83c8469af14c240bc442020ee887f19cc263969c83b784711f2c47840073b445a8ded3dc4555168a93efeb055c29cc4db4e09ccc502bff1c889dbfc93ca4aab710ef2f7ef1894fcfc41f6960e55a6026eee303d3054e27ed453692a93078c380f50da2bf5e7cf79cdda527ddfac1f405cf4bc3487cef94f869e601c5cd437e956cad81d6d0682784d57a622b51cf594330067dab67ad4359da63b51944d42a26bf2cbd564a8fcbe867a2554c7ef98e08b6f4dae09a5f26e337339e5fc7257963ed51a2e91780be1b4f3f29bfb68a7a9a1f36d32369d9adf569ddf714e283da97de2a95946a1757fdd688ec43ed41bbc01799bf6b1c7f0fc82fbe68f33d91ed5d488845456a087f517178e11d859997cb0eb83b943ab23a5a2814cdadf18abc0c752ff09e48d61c0bdc53b8bc4fe161e03d919b33dceb13c5fb20d973ac17567f47415111f0b0898bb1820afd143e12f840a22bfae07dc467b681f7d4ef233eb34d3e9502f22e1543f15cf43bbda198d6c602efa9f7fac9c073268ebdb4e4fb543b4d10c38def9f8cf7802f79b7c2f3894f4458476abea8104be1d9f88e22c6674f85c7f13994f1893dc3c0d758e07dc047ac7d894f1e586ad695f1efdd479fb58310877bc737ec8182c3560b0171c0508b73144cfb55413f29c3bf42df281838dfe53110cf6e2613741fc9356dde29e5baed9c8e7fbdee0ef99dc778f9a9efc7b707f65443bfc5c92fe480da09f2ec01773dd5bf28f0f3747b9bf4347dcfa42f9f37c707d1efc9e42e6cd297eadea43f99f15b64d2a382bdb8f1c6e538b17c107dd61eba00d065f4c65ac685cbe88d34e557ca5b2ef07093fc4e66ed61e33726cf54b0b849f24cd725d5e32aaf951e8833cc59d11a5bf5b47e59413a80ae05b2b7b85ca71cab6008597f0ef6a0d3f2b9d9d7f6f2405c05f46ea2ca691429ef48c36acc9f163d2b159bf3b2f3dbbefe80a6900c59fcb00bb5c59fa32dd90db88fecc60db84fe1678a5fa2f8550e85aea27469fb0b692d66e277013a0acf005e067c10a8ff13ffaa95ff13069fe98ccf74c667bac127e1d761bac9c722ff6850c991fff371daa6a358e1c4a7b4c072189f0aefa70eda9578187c636f2cbc370b7886e6330bf7115f59b84fe1282414fbd19bc05719f0189f198ccf0c7c4f0eee53f834b45f2f1520927406e1fd8bf15c41f4f766a64f86e6868e6bb59310ddafdfffcebd3e95defbc2499fbc7110fe488b8b74fe088ed2d5a12caa1ba1b4609c0def41f1e8b62e698a0311db5e1d9bc784ae10e2c26fee796d5f3905b65cda7aef470ef16939e3fc73389ca9d46f2804a47eabd4f54a9003edf9a9509f8bfe58a5e439ee585ab437e88da1f6d65978aa7f4ab52429fa65267d87f611cb31e54cca2bc95986c1ef203cc1e967805f0a076620c443f40b997c4cb5d02f34db234e0a329be2578f0bc1f9857c825f3d5ac3144283fc717e07b1f6b0f19ba343d2617ce7623ca7e86d645662eb5e6d2bfd7359ba8dd8a76ea91cd19f3df0d6238b60207998e93c54b87b3f02c213a1dd80057674f090deae0b6d0b0023cde124d1b59d14885eee2e51c08f0d8f68bcefec7ef283d3c6b6ec71bddf00d95428d574819e70292bc51ab3a41829290e35614530b02a2d69b622c9e25a2c0f5f85b0a6b2823d96661b17322860ef53782e14de4cf065cd26e17c5a43534ac1165a425cd64d1dcd7c7c6fbc77ac7fd25b6d7df5aa5f779122735ada9036a31384b874cc197cc4d68c1cbccde433072118969e2978b6d946a64fb6d8bb55763769b1b5c86ffdf9c7270831ffa5992b7fa42c2d3a10687740da5e1b8a446fabbd8709b5d110065ccc5e8adf75c80a7ff743b1fdcecfef30460e6ca7ceb9d8af2497d20c4388cb970e2166a9ef27f9e56b72907f92a7e2666e92e830fa9516fae84f6b882b58f1eee03e937e89a60ff9481ce2b28f374b7b8441cf16e27218fd60c5bbfabe2c8e379dbedc5c7e25be58e19610d726662576d8a3cbfb590572ae7fe999752fbe2465736de3127d901b9d4b028fbb118650e3b90a9afb1dcbdf6150e942d64dbeb6b5027115a0652682fe59cc7d1f3e7d8f47ae94c8df9ce3bb0f8fb3649215e8553673ad2007b6046ded51890aded8449765e0c9d2295d780ee3b48554c8f8cc637ce6313ef30c3e4991f042c264e9c0b64ae16226e0c9765565f9f8cb977c37f35d39018e9f76f9f83ba50bfcdae0c786bf2227c2da11d5dfcf961371e617bd2a0e90967ecadc947fb43a41d8d78c2c15efda831c048bb9b99b3a264f9f8cd62677b96bd7e37638540eb85f9e297d13e73378ff5290ce19a181a4cf6bd8ddbc4f57b6e7c67f89087a22c0f562b984e7e5dfbe47a684ad32d3873df2bafcdb27ce14ac7960cdc75291cd176fb5a2c677c310908a830a6351cfd4b45c2438f0c955efb5243bd8924738bf9516fab4d8ece8f180fec3df5141ee7dea0da9f70b275778cf44dbff48a7b79fd66a6d8f40d624537cc9f8658bef0179b3ad51062ade2df429bd3db6f6c2f865f2eceafe85f424be5217a6eddae9342176fc7eb7cf174945f0c5b28af98b17abbfe903da48aee95c1dac859082d16b7f8b18f102c048531c24bab6b10249e4790c5f3226fd40e99ab538a4f5c5b71f0f01f4bb86b6f6d8dc023d1a1865505fab90764b27fff102bd98001518efe3e994a5420599b2e1d190e760e33360d16945a504bf0016799916a812f099a9de9f24cd962d6a3b6c7b7841969b9e4098e78001f853edf27f7f76b7100fdc3f6a8f871e16a2aa68ed71d5c3d4030d3f08f1fda3732b7ff4cf6aefe2a52f385b883d8f3d78515e963160884fa59878b619f13988da178a5c0fec24167833d3275b6e685de1171cae3ff9b7b96fcb81f3fd075fafff15e78fd8065c23290e0a0150653b425ab6cd18290924def3387a7efe946bbbc9df760cbd78a4bf5545cca3863f1450ac99eabb9821c417c72b7532897abe9879e836f97518fd4a6bb24325e82b7ac1745d93df589698491f8befbffe75d59b73ba08b1d0fbbc6e9a94a70fc6bc745a991c3191479e29f6e1d457c6ffe519d9ce150b262ff18f969d77e327d3a73d22f5c9a3df1ef1ee5eb2af4e6d9cb7441a982d8e6b55eb9f0fd332adcd313b0d13f6ac2b7bc5bb6a0fb6f81e935b3d2e98bc252d1730da63a3b32737b2e2bdfdf22e37ed2447f6dbdf3e5df71ad27bc9d3d0903c11e6a19047ad3d6f78269b9e9db5ad1488ab802e1044d3443d8f6ea77d769914b0d017a1257d8e1031019c89b4dbf06616e85187c60a0915ac4c1a322901a6048c7b0ef9caa371c66182b61412dad381599e3bf19db38969b6bcf2b6580f1835c16469cbcb059f05a01fc5ebcea969f5ebc542947e77fd2f77fe24c4bad77fb9b5ea35f5223a71adee1a05eba70bb1b870ce052b6f97e4669f5179c233b2ff86a53ceb9fab62b7e4b8e5851060a13e39d1453b1434c56720dd9314ea547542a4549b3be2bdd137b77fa5f3e55539427cb8fce57b67dd8defc191a30dbb29a8435a8d26f44600a7ac977062a83d6aa9480ebea3fff8162be4eb67ecdf6ac2b5f2c74b4446dbb651c5617aaa95a6a72a5c9d9e4bf216c1f7e7c57fbf80a72615c738e06a0dab34a9fc2a7af61d1b5ce0eaabec068b29776c2fb9eac675bb2ebf40888fb35e2ffa979cd0260dbea572f22742cc7de1c3590ba442fde1c64537fed44ecad79c5fe76cf017851bc4f4fa057e238b37ebbacadf1ffbe57d7f7bffe56bbe1bff93f47c67bff8de937e9dcf8737bff48c5f70997e4687d3174ac5dfa5a1eb375972fe487d256d40fbf64204f6e0ca4a5a70abf8d705b7d6745d458f57d4575ada23a6a82a403f0cfa8a9e6dcfb0ace6856cd3f66c79d68e52d2d7ecba7afadbb21d967e3e7fed9a2fd4df1ab96144f2bc7b62a843b111c030fb3de9b5adb3b05c05fc0197fde491e3fc13bb4237a4f43e7398089ea8d7939da8c74e34132e3b412f76629ac26327f65156959ae85d64a5509655849dfc579eec6434d02f4336d550289088de369af83470bd6db4ed64b76c64af94e33d31bec3463b683e3d337b449ff406bc48f1a5b7b7e6ed1bcb568972feeef8673b3f2c2dc41f462f7af89703a37f11feda877fd51e09788a823535d2f618975a59eba70f3ce2ecec677b48be5cc6a7cbf874f13ee293b27458fb5af8a476099ed4188df87a433d9cb06e5e3bb6dcfda601ef4b393b3ca5550b9c7c48d02fdcf2afd45440ca5ea16c2c828e4953af7590e516062ea78c3ea9a7f41ff87e344cb072a79de2daa327b50ff8f5c03fc91765156979a6ef2779c6f32e9767d0a3f6487ab29f0e6418f4253d17bf96030f1bfc5ac687f741e3098d52217fbdef87d74cea21c43d2dffbae09aa38478ebfc7faffc049ba0d64d57b0f62a056b8e50b01ab0ea4ac02a05375c01b821085f39e1e1fc0ad92f631a0a8e1c31497a36f3bfac79ec3bc9c780c69b7d3ebc64edc1e42d0e57e3c463f21666f42cfdc7db3be9b88bc933e7b7dca0173c3621bacad3e79293fe791c9d8048c71ba499509fec896c2c92eb106d0f4f72ed32d8ec6b1b7920daf38828e8bbf8837b5fd2e318f941a98569e32fbc4d04d720289b293f693e7a099e53b8ad10ab582f66533d48f30a0979c8843c876c58105370767386c573e079f396453a67aea2db785fa3e74fcc553bac9bbde40969695cfee3a039d252fb6ddd4fcb16f41562fde85f572f9296c6bab5bf5ee9c3aa9cb5af2cd9533eb8d4bbd08f25a7b44bfbb6cd6449ef84d08ea917f8efc31a8325c4b764e9bc6b5e3d4c88672bee396cda1baa7feabb2958d71710bb85d67604bc5a88d36fbac4c9919662d7017b753f4e0ee4384bcec5fb14ce0baf62bb052b0fb3d8b2a9a50e11008f2daa3ab8cfc4f99a19da37e5c4d453da4a8b37343de5e799d2a25df0dba75faf6cad5ea03d10e4d737c0b56fa0b512a44b36926a5a0c1811c6458587fec03c62d4a91baef50f2e7bdc396bfffde3da23e651b755fcd93cea2415deb1c5f3d1b86f83d11ec92aa66d3b3654b2f6b6edc185f1d1b053dd90f5526e2aae2913f7490bf88d6e8f77fea0859cf84a1abfa8c39a13c951edae800b14240552b30b7e27c57235f04780cf57b0ee6cfc0e58ffad7cffabf5f7fa86cde7bfbd3d66f63a21dafcadc379f3a4c7bccbfdddff7984348442a9ce9d2d2e4cd01e6c735289a9ef250fadb97b8655b2f9c2d5f4d5df5ded4134e9513abca25eb0d07226e1a647d2eaa3f4fb3aaf918afafd2797bd78a97a904257b45b3585640936c03321b9d79b912e0674c5465e5b5b81b80a6805028bcd5ffbe8b3eee409e74bcb2f549752dcd79fa8f81a44aea013f594fdc13b3469819e5ebb50f7bb586328463a60330bf4f4a2652973614b112ac95779dfce6a4c84997c20269ef8ea47d435ac9382ffe382ca3bfdf32ede2d7eeeb5c7e54435e5e33b4794e408f1c1292f9cf5e63942ccfc7ada981972c2fbf4cbe90fcfdc4f8859def4b299ab25ac7a63d1277f937faf78fdc78fef90f72f7af196e913249d82673f7abe83106b1ffbf9838fbe14a2ddfb9dbeabdd5b88d617b7fd79a7a9b2cba7a78c6e257d9d0df7af1db0500adca30f5d7ecedda74a7eaa6ae7d76260d761a06bcbb13606bb7dd7e328df823ff1ace157ddb28fecbf6b52f66cbbbf0886f892145ec56d2d8173549a9e38addbe1d3c4165b338ba01f9462c6c04b393275e755720a9f31e3d5c8e734e0e0f2375c0788ba8f86ef000fc57de4f253a156045f580a28f1d4f92dc685ce132267c089d3eef7d75a5e74be687b725c482a1ffc4ea5ad4758ecdeb6e54d3069840ca332f0906fb4472c0463d2e715d3961d1bf45a9f650f2eefee86e36a5e17e2b5d6131eb8f578297fe74ccb9b0f43a3a141419af0497eaa7756d07f2e0aa7019222a901443d4e0d14482d2994b3400f864c3de4b31e8acaefbf050fcfba7fe900c9ef4da1533f9d25c41e5ff53ae2b8e512efe0f44ceddf647b44bf3781e19285f631be3f2e09c1a44786512c5406838d19463cb4ce16f503fde7249ed752f74bbba9c3a7d26e1c36ffd6d7657bae7a71c95deb90ce4b21672dc7906fad482628c80b10f55500181149aeadad40c20a680b0d21b3507739d0f63ca9ff0d7e139de164743d5b04d7202a903595c1b6f6d0961813709be545965d31703a8276aab6c82351bcc4f41c028b967c0d82ce639882dd7d359f81ec97e8fbd6afff75dfefa44536eba8e9fbf8f34ed9cb77ac795c76e0cc5ba6dd31738c102beefaae66f5d7b233a778136b07ab0faa234f804de87c80d6a190a8de178c57bd35fefd2b567fb77ef59fe4fb96be21663d2bc487552f1dfae21affececd6fdbf9696da67d7be75ee6b122efd7efe9b3ffd4d3d5f8b350e1ab014baa2815e7b8f1023eebe679fabef950aa9b1ed91071d248203442b00d37390ada0f02c8d2bc380efdebbf9dbe12b0b3f2607d1f7a6f44d9be01f711c99f8cc9269e3d5937a8001d69fc37edfcd847aa0458471f98ae4dcd537dcd173a5102debda7c35daaf03e115e4537545b6da01a1d25c246fc2a38ee03b4c4b36960e3e26617b704328593a69255b2be04923ae28f183329ff47eadfdc37d84f8e8d1972f9d834a0b9ac8eb497e208fe45954fd49410a5955f701c42230290c4ad6a885e751831d05b4070285a23d9c37158cefc7c52fccfe6a956c91aee97bdebefc292176c8ea76ed3195688fbc84ed51093c1cc59bbb6798ade2bd90d622217fb63db8d8fc60ed3fdd4f6c5ef3e9c97fa5d4a49dbd502a882f9e89ccff0e0a9cd6f8eaa128b4a70d83a91e5ba3e83de358faba9e514b44926b2baf81e858311558b9429cd6f6922f77f4832a45ce9b87fa165eb01257e103bd760ad795a25e3cae8f6ca50aeac9ece84a1c65491e8237d453627d29d62e6215b854c16b54bc7bb14a72aae8a54a72aa88cf4ec467c3e2fa89d5d2025ad17ae12be51709f1e686270ebe51b6f3037346ce2e8ac8b9e7e0a73b7e3c480e869bab076c58acdaa5eadf0a6e4001da0614feac8745b10e1dbb6e06208ec05cfb92097ffba709d7de03280756ddbf6b26af918ae5b571138ea890bed3177323efcdc75ac75a646fac830bbcfe44c08f63fc0c7ffeb6c3fbef223d9a5b3bed729c7ff426551c4750d14eed393269c5bbc287072a788b8cf62dd2b1e5e655bc0f14c7014f58499ffe7d871f7b491fb4ebf0bd0777fc5c7d57da7813a6a23d52fea16008213bff2c72ff925ea682730151d9ebec24156a8b76734ed83d8e5f5e41ce77406015e47a6d8e5790072bbc893edf512171c57491b5e29ded7ca02bbe15bda16645f6fcf6339f2b7385786bfcc4111f97a8efae5fae60dda90a560f57b00a9be76c808221795af77f89e15a58c6be471effbb1f228be22700ee61e26b6f033c9ed191cf3ff9eecdad5e92bfaf7c6df1fb6357c5b507af201fca7644f0d891b7d41e3d59857ab0e29df09ec069ed4bd11b69ce634d54bc9bf4279bf2ccf9edda6eefc5bd4f56df9dfabc825caed3fa2b980205ede0e867078a5dcb33cdd330f8935f5bcb034165af660c16aef3b0107d469e72ee215223b678a6658f027fc2ccd7a125551fbc0af86342e5ccacc256762e62f91482ca053e4587a4541a6d6cbb7685e7029f08fc38b5c587f3b25908284621bd97f8c857c758c9bbdc785c8c02de127cfe5344a7ebda43aa57fdf49010730ffee0d5674608f1d26b0f2e7ef93269e1dffecd8495be28948bf2fa6b553bd42d037c4ac1da0e0ad6c092aac1d9c8351898dac53f9fe1f7e2f9bd418f2c34ac65d43eac60fd5f81e37d759840f52239fe5e07fab57b01d64a011db6f79f53df15e2e891f9136eb8d75f5348e9d4c55f7329d66b0eaa1dc6b1131f113214c5c8b2ca659b4fd2a98213a9bd11e21b05e929a658327047870c95a7477510b85fa72d5fed5c055c992fc4e79ee22e7f8de2d78f7e6cf37e9a108be67ef5fa8fa8a9afef04482191a781a37d1aa058745d485841da64d1f7ac73da0cea70de9df2bd8f38671e74b6881d9d9c8b42d3b1e0e31c3a5a194fafc2f7f1b5b97cc8277d5f31a337d1514ba8a728f993edaae885891eda8fe8e582fe14e073751697a24ffcba3abb302aef359f6e707e5821c48b550ffcb9245d2a8715eb6ac8732005a23dd72715acc1dfaba050c820d21e478d096b272aa8c7057918b094ebd55a8668c0f869d817b033e00e0aeaac23aa8378501a53537f2a5e280dd5eccffb1c32509a90a1f9a1933a7410b1dd8c6321f362033f03f34abe3312ed31cac04709926fcac2541ef68e783e1ff4c6e95099c2298d38368f297a537436a2c2295b7494f6008b417f94c1efd7ce57fe32fbdbaf3ffdedd402b417daa9fe74b40fc9f32405699ed05986b4f3023c11ed6127dd4c746b29103a4190425758fd4f9113dae1b79db8f4646971877e4c39cdb764f5561f83ccad3d44bade72444de4a59a3a6da14158e22d1708a72d1d0e545b7bc8e1a6fe32574f402a0db2d8dceac3194d69b56cab8f4af0f94f75fffaba355f2d3c4488c7cfbdf685623991cccd7d7fc9824765a72c6e58418a81424d3ac6bb54c1aabb14acbe13385c77da4db6ea6b4028e06a0a052c017c02f43010abe1f2eb9013063029a2daf780c3c2aebd1838dd079c16316b2f10a2a0ed0dd34e91aabced2e9d479fd943f85b9990a2588c762a403b299cd26c8bf5d25c66f4f7587f291c29b5dab51f450760995bd3e8ad5432d8d634d87c92fa4bec8aad3dc2a0ab4fb653176d4553bba4eaeb6fe544f2f98af28af9ea89687d8b7fd5af003c44c13aaa7f414cd91b0262b4058f0a4644f71a3afc85412baff163eef78a11bba8d04dbac16f3fc261c8e8ad31a0584b316a32743d90c22bd9963763f4d63cd180859ca0143d1a07a400686b13c1e8d9b7fe498fff268171f6c56e919c27ce1362cef3efdff71d26ea7ad4d3d462c2a7b58d2a84a6aa10d9a87a48c1f5eb815f69deaf17cd2959833c1aac5135c0c368c0c447fda4712890465230a45848a1484fe5a78796bd54f5ac10fbfce3b0bdd6499fa3fdaa2e6306a4c5b547265a89b62aa20d50686b96a9d8fa24836ddd53c8fa6f2a19b2a037956d8544e9bac58cfe18b615901bd80a485d597a6562713cbfa9a569b9ed657bbe7fc88b9f3c2b3de5baa535abeab047563d0cd17a0a6da15d2944aeeb419024423b3548ef495d24191161b9b6551aaf1b83ce15a193fc92fc409a6d2cdd8d5c35a4c76e629a2d4f839c03fb912c5aa4d9c6a5039b69b66196661b36d3f2d64efaf932ff70fca965e3d3c6ca37adebf8f3573450ea6940d01a024df0a8abd83055c12a0a59214d713df0f5879b90ee5f3fd5bc7f436f86e7307812fbbb0556810ed57dd040f763d5e3aebbb4ffbfa582a9776b8e7f6fe766a5259afdc5d312cb81e7436ccb95787aae968308e823a4005ca703e3fe58fab6c28706d281cb0dbec067bb833a1fbe0b146d0869bbdac041a84aa73b3eaba0aef340faa3bec2b1df9d0bc4c0acc238fecb59faf9641d3252fc146939758def41ba6edcb830db03df2fca4c7ab1f476fa7e9dae6bd0a3f68ea55bd3f460a6897b7735cef5eb7d3e796d6a8b2fa8ce008bb1e4a9515d904eb2a0c5719277521464d0604d442b0c82f0f4c8e3d031fc6bcddf35ce3c94ba6b193fe4811f117bff8c8b5e7d64baff9e77bc54df93d1eda1d3994d794936efc4cd336e14f7d8bce331f9e3e9ba113e8f9969f881798cc61de7b79fa8f7e5b86763efdb7726b9869c521a2fc9b75e83a690ac6342addc9a7d6d250512a86c0ce377dfba395e74e830387e2059ea006880f0fa02aa2760f5058109c533078c541f141356f727cfef36263ec9a7c2531b07344a8bf4fd6ecf9ff5e43ed21c58347be44a6c62a605188aa31a03aa1a79ed7aa2a6099e4fe870f54901e809bd8a419ae05f37a1ceaf47a8a0fadfe6dfabc047f595ec3e067568410ec486417573fcc5cbaf3bcfb8d15f1cf676693ccf5f9b89b52fda27ccea5492d5ad509d4a38902f6fe2ac9e461431454f8abf0c6b0d49ea2852af6931371ded4c8a22850f3082b48b293c693de08a63789bbaf655fefdde55e2b7f6a78844f5408a8f7c9851b13aa688c9af6950c51946667b20d02047876bb6ab45b1daeaa2787b7ba601b7e6c59f5e9f374fc26f56f72279a42c2b3d81d3c44da150a648f4446e59fcd68be0fd18a4ac210a491d6de281fbb962e17cc9f1f8e5ea8aaad5bdfc7071f527b366c5b547a0ee83d53159e61dddbe5a51139e989e94dbb0412f502705455ec4e9b3f9d1c26fbbbf763ea62d3686d4f24b8ae418f3772dcfb4d6e10286857125af50dfda8be8aec9485481dc2c1e6fe71718252ba0eac90af43c4b819e6d42619e83f440a890d028d86b6e811ef1396fc38cf113270a31fbf877ee5bd84a7d17290ef238aa6169d1c4bd810aa492790228bca2095e4ff83c764c96de5589210ddcc0dfe9f923ccf76885516b426d19ca813ee5ddbbe67ffbad10cbe67cdb7f841f3bf5156c6efc00b158b6dc728e595aaec2614971cfa1b91e4e446f633fd4c02d1367eadea9e7b569a3be4b2b0458647a80918536c5bc2f6ee75bfdfba139c76d481f13e5372f74acb07a3e310fc422b731c38559baac3dc8b22d33e9698f9a8f83a485858c5ff4db8693d7ac5a413172aa1f6069cf5aee69a2ee6b420add9247ae1507267af26878e5b43ee39e6079629cef1ca0d3b1a158ead8fbfcb59afa4beb667d776e5c7b700f2d28c7d4be24c7890d195a7c8f24f6f8ac1e362b90f602111166205b3ccad6eddb4648aeb921a4e599e43c7e3e6e0226bfb676088b34981b070f14f5fed60eda7308685c5de9adfe1e1c90061ea8c48d584226d95481ae36ddf6ec21828402f3f3c72bbc99d2729d3ae49177de244bac8782b4285d43212b4a5f24cf837b100429664c9e045314a49074ba2e06aade52c4627969d8a379f769ba34d0eb4d486b008d938478f4b4d13fbe2d07ecfa49bf0d9ee26725d92b6f9b54fc71e73c84d5733c04600be930cb90f032411e48583d9778e24cc94acb6b8d2c1e3dd0a8e29c2c35b2d0b006a5150d0d2c175052eed465e73dfdad3482a13dc67fbe0e9d8641c394db60a88f4df42ce4423b20b09046131e35574c89f945bf554d5877f6af385f424fd4344193e7408a84e4c8a228eaaf33ef6f2479a22f8242a076d58ac2b340b2f9c3a0430ae668461f38c9b9fffec661f507afe811d71edcd0d8dc0af2dcc4864ba0e23de0a958765848ee5146e9b53c2c7d581bf240489e690d9a1407f7a4499ee90b8405b75e5b69115d33481f701ea0fcb0434e3a6ec2b97bc87f5738ab3233857dcf9d5c76a21e2fd0b355260b56c949db8dd3b907abe85c05cb26706c93396f61e35e7ed6c2ebb5139c7ba5a25853b96adadab5ea4575c83aa9c5a238ad7150e19486489bd3163fe5b943d1e858f07d0ad2e21759527a7334b2d468f16b1120069cce3ec9657036e05fcce7f9ae9d7a80d2807e1cb04401bf7ec7bffcad11d6d5fdb2c3a71d84d8e7b8c3efcabf4cfeedd250a7367efe4816ab7fe09b5a52e52df672726c9b5a9600cf0b6c0a5860d06fee76f8d883ab7a870d4fafbc4d88f7663eb73682cfab43be7ca0f21e8b8df5d82a425bcc686f5f727abe73e4822eb27ddbfdbbd3cea37a097b21a43e6f05fcd09e56a556b9cd427ba8e7790539eddc908176d015d3ba1d157d5e31ad0be92cbbf71638d166f9a17cd1cc19cf08b160d6cc65df9282a0fa0e181cba10f01186935c53012065b3513d0d2dd6421ef54990e4334544d317fd5d7d89f608a9c053ef8e0c34deb2ee33eee4ef7bc97e6ad1bef585c7a688c09e619b5d411edc234be185963dc93293f41f3fb29bd307bf2b5a7f37e8a35b8598fbce87d316832352e4d46f753008abd15f3c54e861bc9b41b9a6ae6da5406871724fe9f2b71e78cbd9f2839c9cd0b8a802b16d12480386d236835b3a44f1b84a5957dd67d99e9ab2765ca4411653168f9e880ac1353d17c5970c9ad7fe95ff13e2a3092f8dfa18e74250c1590ded0d457bfa509614ad29208b4757e2526c185b3be8024178149425d1882c13bd391adb3d534ff87b98bfebc29f08201d3073387b9ed1a14c144d2793d151538d767dfd45bb953316bfe65b767b5f7668ffd52709d17e8f1d861cefe7e387d90467a9bc75b01d7ee02853db76f8b64d2d9bb91dbe83c2aeeaeaf52d562c970ae487e7a645162b0a75df0292278681568bf45d4a57a5100e296c5f027becddbbb6f34b42b4ddb7d39051a384bd827c100c22da7d58ef50d0ec0af202751f7032b0ca40cf5a60cbe805779735f9c5a69fbf1dfbd305f3a4dcce9bf4d1c35f53c1206513a2be406f39429e33853e69cd83da1385806400e982b512e024771b7b2d06545f168bd933e87cafa0ef711e15397d5a584e90691b5a743fdaef477d9e0dda61732bc8c35a91b8784e29024adfcd0a9ce3a3e8c50ce22cbcd7a417dc44d5e07759ea82ca0fff2ac4d76f7df436350b9f5f743628221c3a6d9d0a0da97f9aad40b655165638f64f5adb48ba4920154a59b2a244735dcd58cc59c5c85de52807b22858164cdde29aa3d75c22c4b4871f7bcbafe7f02fbd884816197920b4c6408be6e469b0dfe93e1e3bd6a122a48936248b099367c15cfac0efd90ce7210097d12d372159da74704dc33380d7c5f8fef79fdd892f1f2aff7d7c5ddfa5be27966c53cb5c0a15e842c0701426cbb6b3255b503f0fd55fc343911edea7e8f5f0d692ead1138c6342bdd60148975e740cc7c1bb301d06f93743529303a1d36685fa026b3d14922a33e9c58d0b93be48ba6668f28b71d0ea9ef48cf6b3e229c4c903c90785b6204fdab3cd35ef377b260e92a7bbb957c444ada12ff9bed02b298f76f85c240855631eb085d4692d231892cac53b18aee8f135bfc0a23b5bcb08acbdd8d76815fd224d4f5fa46a78d2876d6b297d8539a524bf6f350542052894474c79f352e4bd3bbd9ce8df939dc5ede20c73cf52394b8ba6634d3c703634559e0e5795cad6b3b86395a2517c8937eff16972e25fbf68cda4aa4ac57f3d424cb554e0870af06a58b0d5773148d951b4484d8b8d503cf5a729a8d71860d97917019207d105902cb530a0cb60449817ffbb6b3eaf0716cebdd0037b2520425f742e4623141c15def90ab0667155e76ae989ad2a5de2de7f94d067c77b4549ce9a469a76ac421d490e5a0ee80c76aaec653b088c34cf9e97f2d215df8401ce2ab2a9027ba47719358fae4d1965e27a80bdc1ee73d97d7280363cd470b2d34b24ad20977267ec5890ac023969057970a706b46b62fab18a77b33d38bf342e3a2edc714c4f928b0820970fc1f0b889dac06d1e46c4f2fb265e640805e803fa4719a75e9e569053123f4f6067047d563cab201f9bb8825cca6d58dda777c2207c24f09ef1f4f5ce0df68a77cfa017ebbfb1c013d2f388df06efdfdaf3823ceb826e9267ccc35c2168c36994f9bb3eea99dd1fbb526d7fd8cc8b0a090952a8ec26e16f25b2abff7b741130e20f462ffad95e3e0a078b142eba392aa073bed2b4e402ca8ea3ca5c132717712e2626e0ce19848bf651fc1e78404345b44ede2973682253dcbe2efa357c29c45723de7978c6e312bf434e122898d28be6fb28588b02bf1a1432d5a06ea0166b05b5d892a10eae7d7da982e4c934c2a2270bdfc3de571e751cc1ad7d61c7006d29128e89b211bf372284a73d3128c014d91eef3dfdec35af458438fde74befbdbcc23fa33c25bf4b6eb41fa84c49f56bb6c29dbb3d65410f55ed2fe540e190030772e015432e862adc29d6fda5f022e08f79d1ad109df355c1a8fcab7a2fdeee105e1bd7aa249fae890b6ca9217663bf634d443488d87591f748f4ef3b6322c65e6be20c2d97eabb2e253916bfa9ef56fcc8bfce51cf9147a670c7a5ad3620c748531673411f49266229e8b94e91fa4e25c79abe8bb3f6e7821ebe558ec184fc0a143eb6ba307dd73d4e1062d74bf72aef200d9ce5f77cfb455577d61ea87bc22e6431886c426d406e2b39a6f7cd0dfee9c4832e78cdaf407746a71c70a05fd0eb7aeffabfcbf688a64ac87e32e5aa58b527e1e20c87fc2ff5f524c7b1f98bf029c013cb7136e84f017d57d19372ace89f81fe8bd19b6bd03b23f1b8107ff3909a234ed3fd93095802480a06862aef179aaf05222cba3d6d06c0363f0f44c469deb170c5b2a1798b74baacc269ef201796422ef091c0b3f55e400acf87459acbf6aacad678747a96ffa5e7e8efb9f1f47fedb672da6772c25f74c797237eb85ff14c15ca3aa68b186fcd5e8058f4d685529fe13ef2342886fea5828d0fa02d4824a96d86e31f6e8286db96d748405701f2841ae18951c5af6e976b8498f3eb075d7f3e56880d67ac5df6fa7971fd45fde07966bb77d338c901f6c0d22e3ff50b79a8745f6ec2fbfa883ec02107823c1af433f017bcc302df7b46f39ac5e995e8572fcba03fd622b7aec836f0b1b07c21c71ef60c8bb597498fe8d3f372ba37e9b93a7462d2d7e30296accbda83f38b3de6c4c5ce9329f385e83724ffbd41d8132d440a97422358f3d36b63fbe1f7fdd8fd488736427f22410865332f8719043aed2022c47efbf5abbfc0f728677a0fb77ac5680f53ceca30ffd0bc40ede19af3846c37a3ffa43c8e8c7f2e209f14d21dcbe8537fba5abe397df2145de33eceefad62a2ad3dc803e3f2abfb6593afeda040c46c585c2ccd36560fc2f2dc9b9966eb253b588a0e1c9a0c8f24162a08c73ff7cbbb2bdd05c85ad0f9efac325617449d66c23a5639ab3d0dbea641ae3d8f05bbe2f7714514d02181b002b4670e2fe88a4ffb5d3f60cdd84f55411d09ba1bfd238fdd4ed685848a7a2c8d32ac9e4b9a4649fdae9e2f6331e6403e3ef053bd82649fdffc3c7849af87b8d7a06f4b0f1f8aefb6542027af20a7e741af88d18ba5931af4e32ade4dfa9c5faa7f60e9a93b75c97cd6df72a8e3f93b465adfa15ec00bd5fcfa9728bcd1fcdd61e9a4d6f451829b7a45189db8b5ad434eef3fbba5e43f756c8b4e237a8860ba78b0504f8d467b9900eb3f536ead72ccd2ade32ade4dfa96ba1d2f58706bf23bd17b8a9a832be6c0e68861b185aeede181f4828665057b818ee58584b6bce9e62ec2e24cf4d8161a1880ae39d1fdd276c5dbcbc9632005427bc990e2a0ad1cb0c543fd97e6ef7a4de36d130616f5d804fdbbbb5c05744c3bdbc4797d80fffd3f9cbee8b8599f8ae0222057fc083d26ad4f089e10a770deef3ce9829ff818d68be9cf27fdee70d23be22eef21d0a78998f837e5b60c316b4b057260f1365905b9cbe859166f1354bc47e2e9f1c5775e601b9a97529f7e921027de7be1a167232d579f7487d0b43ef12e8541dc1782c2e05b68f045dd8d1e07f43c5350ba504efe7eeccde79e77d93af9ef13c45ed1ad3ef8e2b82d2943f7a7c2931944d47f71725c6ed0b757bc9bf4f9e23b37b439bf504ce2a9a00762bb9abfdb6eb26bbb7820818a5cd37388b96670d99bb64485ad32996bf05821a18bbfe732fa517cf9bc85cf2d43e8494f90b46502dfca810af5f862382b64f2980209584cbff7cb05249165f528f195c0533f1b7ffcfcf1f29e8cc6aefe76dc3605109714e102373d078ba5ac71a6f8a581c02df1723c1706a60660913778e31bc07e79592a8425023b2bb0013f142b4a16851ad8932d59057911a367d983ab193b35103daea822f1f4773c6af71f4f919e65dfc543f20ec0669cd1839a7cf81e60aa89936209912221cf85425e3491a937050b356d17dd5fcc70f270a4e733eac007661d7cb010690569a3afec23e22315bc3d4cb9e35951aec5a3b4f45f6cab1379473cfd8ddd934cd3e70616e317868637513c656baead776d170f44efe1138e429b02a09013dfacacb995c9969089c059dc7c0faec69bbd5b7c05f1fdd3734e58892c283d3162c2d4bb5a12fcd2c4f9d60a81fa8d306079a296f91d5f1105680156437c5723148b5fb752fb53f50dbea7d698dd78d81a7f5750ee39c4fadd05ee014f3cc0936c6aa92d7dcae2b2a73d2a3e0ac4819bd002492f3e1127d8db2ddbc0b9428dc9bf527c94aecbf7648b7920263dcb1e5ccdd8a9c1507cc2b6075758bced4fcc87bc31a0cdb5d70871d075c74eec8e02e1d49b14d46772bf6f42522ce499e8901729148b22e1e9d581bdc8f09cde2c503e575875eb65592542b47ba6f30f53fcaccf63c4f4285fb69051305dd754a4cdad202fd2b849cfee512696e3a0a7e202cf6d8a5f31d1c3fe0adbf2da3e1e08d22f93e6b9bbf87bb28e4de849789690492c5d4fbd47d33fda2bf72deb864bea3b9342f09885ad435254214e959c5fb1fbc85227c5e1e2db23806ee2a6f9dd5f2a9fc71a8ad347c4faed748ed7d3af8309780eb1d000ad45259ee02c13a8280ab8f20ab7af9945f07eb204bfd8f80fb75ff03fe2d7325cc507b314f96ec17ca20fac65f01046127a963db8ec215e1682c94d1a8289e22963530677b857887edf0e6db8335d88c38e3ffee21e384fa6052af65bdc02d84241522cdc43d16b26965d6203e305502b0e0a8d49055238fdb653bb0f979ed28bbb757bcd4f9f2f715ee8f65882f6e0f34dd06041fb24f128f95a46cc03e11e0e4649807e62390e1a5ce67cc63d4aa2f764f343585beeda3e6b2054afe1467fe09e83d08b8ee676eef68e350752929089ece832e0864617478a2ba396947ff00ba61ada6327b0691b5b14a73a09bd5680e779e8475f11f1c7bc26333ca24020ff5f2a5eef79ef86680125b7b88a580c3f18630e834ac209d4baddf5d0666ebe79803877633f3bc9751fe847a2305948b6b99e74b26dec9bb9fb305fe3b32a561a07c9f6e002fdd0b8d4dace4384e89b7afaa78f7c23c4e9fb5f5a7b1a0e386b3950c116043f30210f79e93513be2bf20d0cb24d2f7d7849f7478e3ffd7ea93886765b3de323f9630731b47bf720bf812404dd1ecc80b184f612242118f4899e97dc2032e927db43adb97b703de5fd7784b0c46cc46e5d8be7e069975f291addf0dc42b2c41a6d8b60aeae80a7b44ad3427064574b8ba6c5b256ed298b444f88982075488a2c6eaa70e0277a8581d3d0734d7a7ff8cb5520a03872e37e6f2316f81e5bc0e222055014908348146fee04ca43037ccd8c5b7224079f6b7f708b5c5e778fb2b0546b240bc942ed7af65838a48b293e6e79ea106f20a461d00f78eaf68a77e0dc830a846014bfe83731dcd9ada59cb8773f36bbf2ea3a21463c7ddf19e3e70b31e0f1821b7ae3fc9a561f29d812e9eea460d20628988a50570a4261742e4b886d43eee317ed7e5fd121bf0971d90d250f3df78b1caf43db9c35e942c9dfd3de24bfc2dcc66f6ca2e7910bd902f1380f19053ccaa6fbaf191ea5a2675df3e3f4d5f35e207984fa93e80b54696dcb6bfb78202a5f3f567199118f7bb133aefb00372a30636743377d16b7ceaba74ae7a19e12dbe1fcec691d3a8be219237617eddb8357d4435045b6560c54794b59497dd8fd432d1f1f69a261fe08d712cbef6140f9fd5d17ec7370caf3521fefe13c919515df7f7ac700d55fc351491d93032f1ea709d38b9d05ad26d0b1ac527832f081e8df91141aa333d959c5fbeebadc6dcb5c2f0bb277696237e5aaa7ae43523b2178da13a309c5f8ee0467a687d5f38cdeddd859a127ab700e9bf4b5c2e615d3818a778df39d1acc7626fac18af728def2f836030e5b2f44af2f8e7aa4f4092146653df8c1d37f15e282c231df5c8b1d0c5a2d0244a1664b759abd68f18282a937034a0fe592631e1d7c459510ff77cce383a7bd2e445bd1f1a419df49f95a1b7a75503a0cc23c11dc59a299fcea0aef9ee6fce2d17c633933ddd67f7afea13539a2ef592bde13f69f2832e905e49855bc6f9f6bfb1412aa7aeb5801190aa3b4c657781f35e0e20ab2f20d3c5b77101540914b4f03361ff7111eddf2305921e1de8d879eb72f16d129e64f15d9fa9acbfefe6192fbff53ae8f92fc5db6cb311f9ebd60af1ad99eb78bf7a37503e4f9c50adc14de2d20076a20c6e440e1b142420ff7990a07f77ba4905841a9c70b4aefa3ad25b7cce5fd038584b1d0922957f9baf06f7814c60a66738de79215d6c60ad1a8107338701a0fae41cfd516aa493f9fb5ab6bf21b37be5cf69ccbbed3e097eee3fd96766acb8cc373a4437a5fc70f0b7174733a7aa00d60abe3156c814d4a29d4e5af9d844e4be97d81bf13c4a54e873ce999786748fea6249c0f5ca33decfcf2f6a6423d935eaede5ac76cdf228b673256f727d133e42ec0afc7f865fd17777e0876d260723c562b14f5fc96358b9a796d8f10962d3d91af69c416456d2e3834344fc76378ac90109689b650c9d20dc7d3ef94beeb817b3ea11875c280b4a8075c7b1254e95966fe5ddfff9f76d9b6a40803ba42b4df6187b17bfb039ec79a7956dc1ccba26233172d3d1e6ba6b52d1e6a60a101f142f242c28dba10f7b7adc169cf21183a0d83cfe6b5838ee983fe1c331925c1e22dd133e87bb62484728d1bf43c5bfaab3d4b8cd3a7f18bd413215ab75690140779202d61886905223d11ef786f98e38af8f4e508e8e536c92f0ff959d6209286b878fbdab305c3c00d7a4d842813d3e7fd972cc455a45722b7830ad93e1e881bfd87250b443758ac9030acfede74fa5cb0e159c7d2eea5ec2c6e1e836fdbaae3cabdf602b32c2f9da71386b03500df84cf766de9ad1bb6db1566d055c0ffbe56dddaec99fbb631108d81ad073a7990c9d6b6bc246b5b34307921a1251dd87b5e3cb7e91f1ebcbc87bc1e06dfc16cb3281ea748c07792c55b7b3b28fad981f160d24b9a7cc2e88739ceb28c38bfc9ea5402fc0bd7512d215add06c8d64674d616d646a2d95b03bdf7fd7115e731c1c30964b599fc06179b13f2ebf15dbeedf38da297acff8259a389f90d26fbf0fe2b37e8d9d2dad11ee284ff922c2c315bf0ad44127b0e7393669944f1b8504018f7299c2fbec7f61c220f84776c146f7d7bdb3b7aac10a2dbf13d1677c1eeb3fa842f2a80a274c33f3168cb5b4fa258fe70575881f86da1b3ae3ee0deb4542152f35bcc39cd4f948d0d94849e43dc11af9128e495d83afb2760d1d144685a746582ced00fe3a98496a73875cb16128a7bbdfb0cbeb9e5e96a45926ff24d7c5a166f93b5c31cdb963c4d7b7e49b72bdff48a69d7a0a7e983de3b6af342ffd28be9dcf3600ac42f54f4da791da2060ad10b7a50890dcb66f29bd4830ad4d524e93f9b47c9f9e51e6539a3c7e538d7a4a7e917690f15e5cfdbf2da3e8be8aa5a80bbf8bcc17ab22c137b564544ddc77096bd2326eb89c7051ddeb10acf15f57e7efac1ff1a784efffe8ae71014813e9c9e200e8cb21d56af3d8e306b048eff512ebee9605801ff7b4fb8f0825f8ff1dbe53491bec3ecf889c98bdec5157fdc11afca82b285063c6671c506ba69d1f56c5e41a9b4d80ed8a46fb75df7a92096e6db9eb64c3b21440c3e83d966a621656b876cdb963c8c3e4fd74d56b0b98915d3090c41d007bd7e5e3f9297409a2f656561f13cbe2051d26deb8fa3380f246cb60fe797cb41805fa33db43c153143d5ea5126996f2ca1b200bfd6746e4e1ff492ecc1e59df85f12c212b3bd68e0c76ad9101e3be33ae1c014b68a595bc884151226e85885a363bb84ba5d3be016a93486a64ed7854fb0a1f45e40d8be3d85e5a9071409ad89b80cfec12e87efc61a075b17b7f5860d4b608186032ebd61917bf602af307b2eac9eb3841ae65ad6cc825b4e6ce140224a0923cc320ca62dbbc04d791501790d839ed90e82d19fccb6e4b1574c1bf4032118cfe4d70b564ce71af42c15d3090cc172e08a5e85d06748a691e2a050d5cd26d40587124a0fe43d78205c514536915fdede241711835f8bfc26283f30e9894df328adfdd75c8f72bb5cdb672b13da4a2412fd816b72c287b2421f36303d9bcb99bc90d005ce2d26435052af4bdb31234388a37ae6ffb92fb671d78ae358c0330161d3eaad1a6837525220150ce2f73f8c271206c422ba5e03920a73f8f9b7add8ffeff2df4353960dd941042d509b0270931494da423bb64a6fbe66669383bf78a76e5a2358affbc04f389ecf80651bdb4287cb6b79423eada138d0679b516e6cc5b4675b1b48bab6a1432606fda46b91d77ad7fb7b6039439defd26090a552a8ea2606e31488785e4cf67fd7f4b807b599fc7ac93ca864060cef3fbb47e919f4994769edbf66eec1e50ddac2e9e9cdbab68f07a24258c1c530d352a0dd4bf9c0d96897532f629207825874924577746cf76107655d7081101dffbe53e7b66dd52704368fc3feaebaa2f64605b52281cdeb44d0062ef0dffbda485801adf890beec2b9094c753d7fa0aa4c3fd3bfde94eff00a172f1564affe4ed99c022e7169dc23736db2e5921214da052856c424b582fef3e5a03b1868ca278cc80015f8158b82d04a3cb504dfa939379668943880185cdd706ac21183e719af4ad15ef9007c775a6fb85827be51c7af8ae38ab9bc64b2205b2c794fd3a75fa428ea10f4207ec382e48cfea416d24bf493d289bfcdafacfee51961bf439bf36cf3ad91e5cda10f8ef590351b94bb6c5256aa0a17ab3bda6356f304bc1f024122c62366bb1953a36a543daec2e63853876af734f2b54c10aad38d2b02d5fea01e6ef7c9b6bbec74f4071b8e2f779b9806105f44141526e46f4bab7d5e9fe00bfde79e2e8a3134c1cc916592d9b5a5a074a320b976fbe19b618145b7a2b45a4f1c6f19dcbf85696a6cbf6760bc4c293acedf1104cbe99c5d6ec8a69aeb0051b5fd6104cd3e9a4d6f45ad65fbdcf3ff9a2331f9672d323b4418f17185cbe61e6b4748ef3d73e8ebdef9c23fe7970947e91734c7c7b04264ec3b0b4f21b0c1945e2bf7b63f70cb3f65f528fd2c2afcdb34ee651825fe97ffc776c65e2dd2d7a4721af4c1ecb2a88e94cf4b0ae4c0e1b38cede8eab10557fb79d113d5c552a4baa668568cfc0da48763c2e5008d6e9cb9dc5e07b8438e1a00b773c1ddbb7b73819f0604054d2ea5d4829c445a12d0c140747e1d2d2885e6cef96b8cdb6d94567d993a7419e07f80d2d938ae3ddfbfaf5bf588856b9e9a73cf08c4854d14bfd659c711fa8e81d8afafd7c76c6fd4876a6bd3ecb5bf75786f13e8f9d40e9e9c56b920385931c3cea6d4e0b052e6f847819fc848defa509295f2bb8c467f1f38ae9226b653ed157f42e853cdb2aa67bea1d194cfac18a7793be67a9c84e5ef19e983e3bebbee3f53b7e70e435429c7ffd9dad1f1821c4d9ab8b6eb9f45121fe9c5efcd5e819425cf8e2bd839fec2044db833b9d3a647682f618da7485b7955fcf6c0fcd6fccb04c5c419e6c070cd67f62b296df9e06fdd8f8189b905f9b7c8c35e7c9d859ee6cfe7ac74355cdb6bc52b60e591efb8fdfcb66bfa5b9ddcf962eac13728ecd2c88d650288f24476c88c230f074f10b7045ab549ff0abf032e039f821ac70799f898f067ea6889ee2e15c2556e1ef61d051efadc47bc3f2cd8a8ec233804744beff5dedfb76e9d6e74a213ae7ee5a5f394988851f7dbe68d10cf58a86110ad2aeb41edeadcf032907a423631f071e018ee771d8e6b6bbf07e0795c2b4581e2a54d04f1638bfef98ab0f962dd7f6b78ec7bc395dfe385a8c4af763da6384f2cb72d05ea3142e9522b5e7e2283e1a7bf5e4002f134abdf652fd4167d3cbbbd4dbc33803ba549f5c3e0acf293c47e192bec2d31d17f8283cb7187801de1fc5ab0fdd307ac50a213efef8d59ff1d9faa8e2da5a138f6e06e9e37d156c64e7a0f857f7f483a674ea24db65c74eb346668ba0bc66002fc3f7f712fb01ef85efcd029f6183ef0cf05d06bc12f488fe2425cf12df318a4fd5f2aae88d52b8ec0793fe18d0cb51f4a55fb418f76502a7e7e800d47483df9c00bff0cbf57822fa99c077c4771ae32bf5bdd4b6edf712a275a4ddcabd4e95704d7af77dae95b256975ad9b95f13ed3117e335037c4614bdc0f81d13e0b757427e2b402f205f49e6034bffc9bf621e73480ecf30f8b5cd37acff02f3e228d02bd6e36314be338aaf98b770e70f3e1062c1ac590f2c562d163b829bc97775b582fae454da5d3c817c1b5784ffb03d3c90a1d87a90a5d906b22b82a10dee1a96e3b9309e4b1cda2057317022a1356b83870ccc90045cccdd4ee879cac5efca7efce4eca3fb623b6b7e1e8276d1fb2ba8b7af2605cbd748a8d23b0218165be772f13e87bd3fcfe4cf57fc5ddbef3dc6df9b28fdb58e6fded53bda5e22e53d114cff8c850c9565172cf4324353d93c446973e193ac6d45588832991c3c4f6b0a5be6f2b2843a562cd9f6dc96906c732ba603a18c9eec402916e24a5a316d5bbc4d16e22a67f42c8bd9942ce0250b716d6c7b3437e4d75c7e75882b69ba6ef3f82ddaec1025e79f3c26d7e097876ab7cbb53d16d1c77b9fd5bd99a083b9c0bb1b5d48e8e23e72595ddca7f06c1d7337cee26e6e0c9ec71c433d53f6e9226de78ce3bb0d3af21ef5695a81603150676ddd68427da00ecbca7278e8886082b459f5edcd83d60247dca60b24c963947c0e5a3cf2067fbbee218b2ffbfc057f73c4494edfa3de12cd99e89ad79e939b793265b2b5ad5c8db3b52dbe28acf0c6bf37b6a4f35e6cd7a60c49ab3c85d9227fa0308d2dae0acbe2ad6e4fd09bcb0e94d28bb901c3caa4dfdcb468c29b5b31cde421704055330d8ba4ed212c868b7db1b9697e2301c5b479fc52d2446ceda579fc0a937ee0802a7b01289eff2fd98db7f1096f8775eb445c077b346144f1e0a2289b5002f504cc73b0580a34619162b26655d82c66b61856fdcafa57e7ba427cfaeb1b67bf70b6fa369dc74ef03d40f240a85e843c0fc2c903f81a907b0604052e97dd9704ea1055317b1f16f77581a4541c7f1e72c327fb4d1162cfa507b67cdf5fd4ac087903fd4a61bd379965719c5b5e490abde20a09c3f8a6c472d05c4545167e845978ccd3ad3fa2eeb9eadec2bc2249f0262e0fc71a5b2d455abc1daa0bffc2e0c79828ac3b28d82abc7b363dd107dbd3b2381eb46c153ddb1e5ce58c5e7031dbc57711ae9edff40a72b33d62f2602896048bcd090dbf00bf76c5caf92d4fc82fefbf60ba6ef3f8b5f45fb33dca27bd89629b5f5b6b0d8426b04a05e3d7407a3dd9efe5e356c8bf8543571d70801fc3c4aa8583804d1831c0a93ac61d8dc43b154e4914cf54e548f2398557a23c29ac7087ca95328147800fc28e5548e795cfed07fa613c67c64623c0f3c0970bbe4a15bee0a14fa68d8b08f1e5fac805f3a020eadf04a4d8e277807f56509f6088a9454f31f466ca72c2d6283a7b8b26fcef01b13641ed9b4c8184ce33e984ba034a7a47be70daee6d4f12e2a4ab463e71d96142a44fecf0b709fe1ac7c14e64a779d176516fcb75c64569cc546b0cb27d5db4534114afd46b10515cf6978baf527804789e8ebd2316ec8c05aefab954cb41947bd98b613ce7e0be30ee73709fc2a7ead873897a3f62fa313988e26b3bfd7cdcbc2384f86cda9b8f7ddc463158f7a882b5470222565cfb06fe8e359006f49fb748e82bebf4031f89ae81d477ba076b20fcfb33812bf9cb51f2a7e5ab92be57f99b0ee199c023c01dd6be33f59a613edaa94979d5f4757bc2bfd5edc9fb4fdb2b6183df3c46af8202ad8cdf4a920f3d4e0b412d8cbbb3d03a267d27497b503b64425e74fb307948d61ec46fa5a4a0e8d1bce25af87512f2cbfbaf02f4c2a057c9f905ee30fa167e05f1e7825e29a35fa2e8adb8675155740d64d2ac8fb6dd1ac8d6522098d8e237d98bbe4e4e643d5fea3b39574e9c2977a6dc72b8bf9d334d2861085c05f06c35409c990e2d299b1d90870e70f15ca9a06955e111e079c0b1062256811b5a2c2c8580d3a27b09f03ce0b10110c5d79df8eb159f7d26c4b41e13264ff2f320de12f7345cabde5c3b5dc1fa6b00bf55d0efa0837f1b58d1b1a310bb2ceade316589103fcc5ef8514d0d38a6897e0af08780d3444f0aa01438790ca4602a4c5cc3bf03fea4a01f52ebfcf42ebfa55d20c4397f2a3ef01cc9ef6e55fb3e3579a5fcdbcba97d4ff987bce91c71458bbfc60df0d862a65aacccc7845c02c59ca7db4f097405c363eda9ee77f17c312916a8cdc040b44ca495f85a3db08167a39f676a3988e0bfc46714fff5c455b77fb583105f8c2f5ff3d93fd49db5e8afbaab814361d420345987ddb31a707e858ea24b8a59b30ffa47a7355281ccefe88cf44bb91cf6fd3401e4e27b573b33d577e9ef75f1bd99e0bb047c67826f931eb56f362912935edc045890903e53a8b23d39fd4ae061f05f9190bec3e897307e31e169032fa6a8ccfe2b019ed7ccf6d0133d53845c1e92b5472c29210b6f013dc8fdc6f30bfa307cb46205fd08a36fe7b702fc0287e2d2e383d1cf54f47e882cdc3faa40e67e3af18faf403021ea45594c807e0867df1ffa9cd2e329f9ea7d53db0e9013999e504a9927518a0ec947d64aa5d960b109857548a5c5b219048fc645964e31d3e415014b44e198f81a3eab7f66cd0b424c3ff95f9fdcbaaf101b0a7ecb589fa9beab1e618c3a84b2ea4881c88e69f9489b6ffc0967c053856f4fbc5188aea17de6de9c26c4411dfb2fec7982103d4ee9dd77c3ab422c3ce0f31b964a8bb7eed39a17424fc4dacbbf52f604de9de15024baee64490c4ffd6b8b23529f136258f1b517f4f95a7a1abd073f7589e4ffc05bf2863f34d73f052eedecb37c3ed39c15ed4f89b64b816a778b27912ba23965daf2cd648adab10ab883fb145e499e04fa23a6384af01c5ad53291ba946dc7147f29b27df2b545aede93670ec4e5950b2eae9053e4bccf663c3c1f1e07f5572d2910f2440e347fd7d975e441ee216787d107a5777e497a6ead3b7d3c72a4889727d56e427bd0ea7b33f44451827623b98f44d14aed4147c0b7c2631e4821be7f1cbe57194236455dcae897980a35c06f6c622b01ff9906bf79568fdfe4b752e305c0897ea6413f93d14fd61ea4b8207f09e43673a3daa342d3e386cac6f25b62d00b7a50aed11e8e95dfcc787eb5e27341cfe251ae7865d15dbe02f9f6c64fbfdc760a24d572e356bc6aa755fffddb3f0bd162c7562be37ff7105384580b6f2835b8171d289e70f0772fda615e9ec245ae4713be8a090a86e7295c60f15c52a5fc6b81f7e51a389d1406e527bb279a293f7b69c583e33f1162f5c0a5ed7e3b053c66016262a7a36e756260b110832b2ffde06f525186faa4387d7c8fa34244fd8ed09e29b7f80cb59bda39922fff71d6f9452f2e6b2f3b2fad7ecd47e7caceed5abb6ab69c98aafeb5e18c6fe64bda4b1a4eae7ad727ea7cdff896042f88a57ec7a79cd9e2cbd633846895d2e6c17d0e90fae0a116bbf798247fdf3ded8ade55f23d53433bf4f0155cd851f6f60962a03fe57858dc73cae94b1d8aa9266ecf32d51f5e2f6f14dacd453ba9e9b40803b258b5a4a73d00e0346121e6ec50619deb94e339d5af61e0aeeee772c66739e353e143892ffd1dc5ea6e2d07517cd590657badf04bae1e93ffbf0bfd76392079162e703a03fe13615e11c05c5f8978ca4fb9cfbb25f66b549ea254e4305738d6689c71e057cb25e4ba58f11727e70aa7f6cdc5f3114d4f18df4fed51eed0da05b5a7490f752a7457805f4eafc2c403fc127d97f14b6301df238a40af18f404eb3f6a8f5cc66fa03dcc792081dc6e647b00af30ff1ee097e8b949f80db3792af9bcd524bf02f22cf1c4f489df89dba390705b792071b1fc5d2ed8f352ffdf6d77e95c71913f95c72c9e523c0edc1a328944a13d26a8f03ce6499026cf77a28122672ad64292844c7e7df7c7a73e94137064d65357bef28a62b01e057fb51d15a41879ed55313cf7b6337bee2fdfb4d3d2ac95637e94f416398f473d31b2204bcc509cf38833a3bd7c3e7476ca91d9274a45b0a4e55561c941ebf5e9f70c1922e19eed27f99b15b679b7dd9567cafb5aa7b7ffe02ce9f1b4fe579b7f9d2127c0d4c6160f1c3b5c3e7f7aca80033b487a5f398bba74897edf587c5f217ac1c5f715e2fd61b49fe939104eae7d01428a654d87f8b4255669099938da9388eedd2365a22dde17c6fb95f4649a9e83954f41b8b6f00b0dbe9805fafee1cf1efb9454e86bd6af7e6feda1e837788e7aede311056bb06b56dd3205297b8b3c11bf42216bc881ed3a7f293d909a8e472a0f24b036e002577b15e5a8ef6dae076db53c4b21bff9e897580846b5970ec1f0b5bd4008c6e457b72ff3a06cfc06d6326c2118e641c5220a8e41df491a51803c680f44d12b65f49bdb1ee411f39027e7b7c2baf6c2db43d1b3785071f356b3f88df3d84bc07f5e227e7f58b06848d403f9eed367ffe3ea40b42527a7b20f1e78ee81cade92c98b1a2e5fe81f2c434741f6d495a10a1fe8758d3e333250d9a94ab3f22d95c954e1cecfe2a60387eeb69cc5ed253e8bbbf2d239e203ec1e4a0ddb8833d21b309134ec8bdfbf92f3c3f893bbec7b9d9c585e3ab0c758ff88db2fbd0bfdba095e912bf9322be0fba0f29e57d2db2b8733e2f98c3be33d17f4a892351b7fa7f6cb36db13672bb3b3a1637ca25296ce92d7edabb34050290b9b932a673d9da5427c16197c0ec711af492a86359f439354bc0f44ff4ee67c2abc2ab476dc1239757fffe3d7b7fe8423a51a719a3459f3d8a54d3492cdf70c203c138f56e38c424f6f77bcc794a79ec0e90cf2817a13cf6655203751e1ed815ed315d3aeb562daa43f3640dfb2434380df9189f8f558e5bf673f233c71457673e561632bc8f32ded413b2024ab20f72cedd133d01e43f15c86c97f604705ceafd11ebaff680f35be6303e7f76641e5c9dbf0daca1e08d96021dabae34f7270ded4509b22e13e27f72eecf6a1fcdb8fa9837b5f29fccad982e83dc54e148a7f8a0ba37095ae1ca7ca4e552d9121a87254e13982b2b6e6aafb6091e2140b0ac188bdc411784ee0b9cc785e79c57bcd37ebbf59f89d5424f3befa753ead6d7ca9602d2cd4fac142ec11ea35a59d9c120f7becc45f1f978a24f459e8881d2e13c10ad45845ee06bc4fe17d54e5bd3345bf3a33099f39f17ccafb72709fc2ef465e382a95e32a93d3f13b55e62a3cc6673ae35355ca8e4799232abfb5bf8837c6f19993904fc2c7003f5074c073613ca72c39375041adf0d1492adeff09be5721e9220cbe4a15befcba6febdf9828c4ece5ef957d75bfe2a516753bb4585e8bcaf31aac79d41cab60dd170a3674c6378ed6df2eb2661f98d7e945e981ccebf8eaa874115be328831c0f42bffd13df5fac2dfda62b90b9a5cf2bc8ff097c2ea3576aa9201f64a9c8d6fc6afa838027ab984e6f92dfa9849b15d3baff908517b76341f32ac87985f7665690cb7e1a0b3c2721fd58c57be2f688f19b6ed0cbb1d0b3f36bce07d47f15a09741e32c31bf2b672dba3eea814cfbec95641e48d56b0a363c06f87b5b440fd429c0e9d27510d2f3d9e3ed035aa7be2f44cbc5adbbff692711cc0629c59444698a3cc445e9bf3aed4de17169a04a40622118ea10c55d8e0e7544149389171bd3fb75ccdbed2d217ec95ef1d8c77708b1f6b39feefa0d1349dd3e42b45f95d1d5df96fad813fef2d66d2b84481bd36270d613069f3c64e02a3e3011c4421c6a5ad2218924d966b16c1285f345ed4148bb8d40b16e6c9a2de793f89aaa27e864a102b8f2ccb5a750046d499163cd0aca049f25782e137c2a9c87cc4a11220a2344c4425c9f5ff476b749d2535cf6c482c77ff841fd81b2af74e88a14c859c0b1cb320dc0c67f29a8f7f3952dd3ede6ec99edee12a2dd1e9d0ffdfbc922b8784bf254aadb75a6c91f5b5ccdb32edee6b1ef2f003e135f1906fda8bcc5a5eb2a7ab6e403c6afa45709dca4b7b1fc9201a443386c3cd8b3ee4cfa7cb19916edad212ed06f667b68c5c7435c443f9875d534bf791b1b924bc26f01e805e60393dfe58bbefdeadd638458f8f9171f5562a6ac4356282581105ebdb3820d6f01feee14485801ad402a002b01df11e2a7ef97edbde25669c1753ca824da22e7893fb5e9156d10377a139d3d3155ea784533338a2749b3b5d601500cba97eee07cd06972a24b7935e59bd62708b1fb7dfb5dd44f7a22dd9edaf74f6de590dd6bcca1693dae1562ffbfe4b62a9478cb35ad77df7fb89d4f6bb6190db05ca530e574908ff76781cf30be2f8bf19915dfda4eb06e057b046d629a2de773aa4e53dc0fef0fa37d2b4c3e2d69955ca1e604d2ad238ccf089ea3892d62f019cba251783e14e654f24415fdba236b7aac5e2dc40be7dc7be413d270f17ef56eaf437d07d5799002a9c1e697b5f38123cd9a62c58dbb8323173053fed6507fbb9f7db7dbf2ec97aff06dca2c35c429c9404a53259e214b14dfc9fa3fd34c7f4dbab657862c2ced295aeb5f14fd4a4bfbf2fa873cbd984efc6736c56f5c9658627e0ba0e86213a0a217933393be3d3d9ce8170057f4820650e6c6b4475c9618975b17ed53b091ed5100fe938d83e6f14b6bb781f9c0a4bfe0da99f3a65e2ec4d286f9e52b919e54cbb20cc910aa56db98c6d640909efefb5320d4642e704c797e3a6af51deb3ef7ffbdf7f8c3e775f33751bb2ab5dda17ec8270c4f424f046a00264bb30d4c287c51ac0013dd384cd08360b9694dce3a9ce7bf0f0c7dd5e238e991fcd0fe929e1749d8b7e3b707a609913a33756c863f84c9420f2cb6f1c2246dd917824fc2d57d194a6126b0f00a0cfae1c0c054f793a7528cb45b72bd791aa85600cc62aab428d46cb8de3375ef96e0b94cf05982f6cc447b96804e26f82c019f0a8f6db2478575ea3dda1223cb0b78d0b233f99c4aa13933bd7445d577f3df909ec55713df39f1f34e8a73aaf3a00156f30d202990f1c05127528f901729104ae3f525e4b76f574ff57baee74b474d1979bbfced5ab14bab9ed1f62835f82b259ccba9ceae528aa61272a0e5ded24f836893cfa63de88d586cfe7ff2be034e8a62f9bf672f9025a380ca9d020f0e13064cf86ecf848ae23360fee9617a2afa147366c02c6605b31ea2a21c2604c4802c0a2819942808778020395fbe9b7fcff6b76a776a76d8232afefb7d1e65efcdd4f4f47477e52a1c50011254d0beca49b2ae0a7d125404ef9918bfcf3ddc67ccce433f27117ebdfe0dbe60f765cf7c308325d7ad12125ff5e7230ffd0c8c9fc69bb1cdf908fa7eb94c5873c5f83de39ddef8bbc73e3d5433e6f3963fb601ebbcbc25a09044d888fe9681248110646f44d922f287dd4540d058f200e1905e596e29d8666d3267ad3b5c1fc80736f8e6aaabe2287016473e93ee3de18112a832c9433f870f428adc2537d448b41fa43291feef32e29d38f26c31cea481435244463f9775a36661e7f838521a678e679c7ed5066da47cf469fe32f17c332e252487208e890f408cb3bb6f434680c7f49373baa6df9539bb7e98a75c739f509df954040104354bc4a9b884798c52e3c6e7bffa8626186b162c7b6e3d050e529c07241092344a8fc7efa4d26a6d6005d2f53301810a8b332de8959655d079e3156e40696b6b73e326f1848e37fc5d98475a8761338fc954b13e158ce9e7132324f0258d9816eb404a904ca899e3eee1c15fe8c59f34e2bd95c9fa54797f45f196a3f461f65dc9bf574dd487d8f95b2f58a219c9ada91b9fff4d4b7c459b373dbd48cf6fe5191543369cabe77a6de58325aeae3ed77ac5fd8ea14ea189355c47e92a75a575b54a24a1da78cf1edb331f715e6211dc4784c9c67d3db6673ee2bcc4bcf882c69b13c0586648fcdb96287f9830e4990fd3f51a5e5834abe41ef3a07214ee6249041917988020d0b90281d0aca26d8591dacadb0a447fb711103c8854587c6481907060a1fefb9211b316afb959a97ffdfbb8369df546b7daa62c38f0611517482874c6d55599f007659b87b131c402d848975f88fb6cf4cd824966832095c900783f7487e4e0e71472cd7d01075f06a78e209b407fbc5f0fbc9f775c4c0004472a5571745005ab0a3230ce3ce0317dc93111a1ca86dbed14b8ddfa360c1f505675c669e5e33b74e5f9a571e68871e6c48f3390a092cd0c81849b4e5fb376c6e74a7d73ebbb978c4092ca72a8a658f280c44184830849590b4018d92b8719c804041b8cddd3dd00d91b4f7ca3db3efab7f7ac051919caaf82f1dbf4e43a357d3ee8f940c930d789ef84d43cac8ab5b62d41c7addf5c8cdaf6e0cb912a988088691530de1fd538373ea9f8aacda316ea03695561c1bd63aa94faeec2813d5e68a0d4cf277e3e65a8dec9bf2c1933e26b3dcfb33efbe1b988be73ce27e3d7fcfcb35273c74d786ea296e0667d3076dd58bd4266fefa7dff516eca99bc6f2bbf98a9ffde64c2eccf349e0697343b75c3adfae8da2f2d9a4d2aed98f470e30bf478d65b75a3d9af99a14c12416e13c1e1ef24f75726e623bc5df3919324c096e62ba39ab697dc6d4b50554d2aa7b881c8911b06bf936fdc8d54b949f41f5bc714208bf5cf2a2c100eb2853001a1144b11c00215d076b304e233a60f042c04a4941c9a13699ed2face559394aab5a25e2337ae411f58a43289e0eabce8bffe140fd17e9c686bfad238988f0dbc1a1bce463c08734e92334b628320954936ab76c039f838051a578e679c5244ee24527bf042dfee9c46e8b32aab07ee8be0fd7230ce88679cc93826da304d49e514a03a1be84b71910bfc369e67fae09c351e43c883547c52a511e49f4f8176530c219f78c0f0975ed51b65f9bb0b1f5b897a2de5a49a2255158ce52597a04fc64682cb0dac34456b5595e0ccb0ac5548efa3b6bd8ffb2c53cf586845ea9693ae8c9b570b57d33d03b76dd3ab6e04b95ecdb9d17e57c697eb998f64127450c47b8ed99d3e094a8cb7f2c18ac65bbed4f3fbc0c289c3ce576af49fefd57be90ea5a65c3bf28dafbf56eaf7b9d3facc9aa5e7f6e32d955b47623e4917ffade893c457e6edb30a66812bb994bee81e7c0b9f9cd677eeb14afdfa4ee4b9eff5f798bbfea7559fd557aade7e8d26ba755eeaae6aa85a3dec563c4c39a55e370fa396703ee2be5318f33316f313c6fc8cadce7cb06a96e7910995b99ff6af94fc839c5b32d8092113fd30eecbc4f8a3fd4d87aeebffeb16a5a6bdfccdd21f0e8acd57fc7c32240282f5ceaa2b8a6f5a64a08f8004b6dd4d40c20670c5bd5c401bbf9ba956217d1414fc3e73e4b2f17a237e78dcdc937bb81e5ba19f5bb81bbcbb9114f4673264278737a459e8037d3a63d3cf50b4114c9f921ddb6634fa5f8fb1d5e715954c65d21d2a890170336e2a24079fee5970224c007c1c79d8e0a9a6734090f712a5f6608e97cf3be01792838d71048d930209d724519d091b848fa0c624895cdc9738a9257362c992e211e137f3b765fefab4394d951afed880eb3ea9672e6095153616491cc489b10da4b981ecf688acca958d0de48d6546eeb1e91dd8aac3b7558b95aaf951edf2fffbbfb8f1865925553d9b1ecf2347b217e23ad3275b495756c59a7e500eae205d7b4040a9ee1798be175fd5db15076d3e52a965dffc36fcf3e95ab298f0ee9103b464372ffcd393335fd273397eeb7745501e9623a92879b9b16a909c1630dfecac405e6f046581af050212613951ff7f4ee9545772fc7dfcf4450b75ffd737c6fedfb097b5a4f2bf669b975fa7094a9786d35bb9b9f73e4e5d52bfbef2d93294cce955fd9c6489e7374718dd837270f99d26bcf8fd4e0863813f1c8fef8fe7e7bffdad5edff3664fec3717de55c40095d27c8371622fc3d70cac80a4c25e58309ec7e77adb76dbdd040403600984fa03012959e05840dd6f7c7dcbf4dff402a91b6a78d6655f4739ca4894d0c4447d7377a1d8a031ddfe403ccbf4c998c939b070e0efacca6424249a6c1cd06b701006700a499304766523a699a5ea1bed22629ca6df1d0b6f249c0562a2b10dfcb9789e8d71e6e279369e978b7152dfa8009bb2e440787a88fb7a609c36c69998a0f68117117b272551f1c5c69981e7e5457fa7fe0fce6dce051ad4f938eb39bdae572d5ff2d15a24916495155454c481913b23111096401099ce223e558a8c0016284f7373926de8f867c51a3dd3ad061dbef4262df158f7584535baa81867db9d9d43e83d0d21118c449c243910d7997e80adc46f746709c4cc73908a33c89d54d8b4365eb9a6f5142d6b7ffdef37cf78aa963ea88ef8e98e5ff4015d3ebae4fb121006962828abb17087269d3b3b2790ca10991b28f29fbde128a383cc5146df074e106404a6cc10e557e843f0d9cacfdcbfffbe7cfa9085bf2b353bedc71786eb757140a3f6dfb939e46a3fbf4fd6a13747e73dc3cd6abdd339c9644609697497e78cdcbf7e9ba1c147b69798d13dc3831fe39df4c257a3df5fa6d7fbe38591b553314ff41d48454b8419fba0e45ecc1b083d491eaca2a53437052a49db5391e814d90b33334572bb91db6ea3486e37abed84a3f2374efd4abfec1d251d877ee389e49491ad3272d61b994cf5422872f61a53f17b97d5e26e6922da93d6e2ae66c4bb1e574bdcd7d433ee6435918322f37b7104bae127fa8b08f7ea47bc9b3e229fe3e6b7bb1867f7f871aa21de1af71401cfe3c4fb6aac8923e91d8e78cff6cc4b40c4fbaa37969e30e609a5664d19f79f455035957d602067d9ad0f78adb75f3ec30b2b071b58b5c140e74640c70bb9145013a5d63db77c909bf2a4626ee9800fdac67f7facd3e7f07ddbfb22c8134720d33cdee4c8086c83ef1ae0eb9db8c6bf9eff1d8a202ffa6063c96f9a00cf787ff4214f6b82f1c569cf5ffcbc9ebf4d5dd634580f89acf41c038bc108163d6de0d62d066e419afccd389036773170d326c01a8020001b7f42ff0b40d89c36e2ef9b7ef2fece90aeef25f00f8b3da7ecf39233dd710f1df674c4adc13eb1df975bafd4e3da6cafff6c74e7f875b5ed08722728a25e6694101910f4f9b0ed08f2dee25c9119001c276cfadecc0f5b8fddf4e4efe97abd6ff8717421050652660c043af3b94a9932a89c04dc7cb9d436f5b30021693bb35592b6bb25106a1103b8e21ec111806b705d1ff46f763db4d2de99fd88524dd20e987e855e20d62bd6e7e97ac21445a6f60307c691c9e0f038b2d54402732dee4b0d3dd57caf4985c8b5b8d99bc58c8a543e14f1ae0222de6f374911d56aae5b427efe05e89be7cb08e230c63150f4fb21f2be3bc67517f07642c46a2c92dc533b9e8de532e2fd24d4148f457a2bdc9781fba865e03a85eb32709dc275a68f4340cf5f187f3792c85ddedacd7191be729c32e2dd685e11772b23e9154792f3381346bc571554dce3aa4e46f47975f9b3fa08dce26c98b7f94b7349e9c10612a75c02955631245fca75553addc032a46dafc0015709c9a48a529d08f746ae24b9af81218ddfa9e5349df6ac7ecda733deb866a9fe5baef559541239dc7c5f3dfed518ffb62390791e5912c13ca27f9cf922d65052a18a752a3309248920affcb9fcd24d1d95ca5ff7c45df7e87db7326ff147cb911eb21c84b80c11fba5eb309f3f623e3f0144a1ae22d4d62f869341515df451e7a6e439c06b808ff09224422a97530141c859a5456ed894fd9a545a22f2ba02b6abf217d03f52a93f272cfa6ecd214afdf2cc98c563c24a1df65cce92933421497d38edd7a6ae8c4d11e4f062d4fb8d723b542f829cfb5c86629b11e4b1887781bf9023f60b300e05fcd1fb7f9ef5c5d32f6a867b79b7853dff840a8a5557349fa980ef63beb09e4bb02f2a487545297b28b50fad7322201115d0f61401a166036618e035d3aa98bbafde226b1e5df244f1c94ab5a8dfa6cb2afd42358beb6e3ac3a5a40538901947a0ad804450eae746fb1d38421b8184425530b67aaa03b6a1d838f0abeb66eb4fff6cfa490309ab19a0276c05d5284813c17d34ce8818a71dedb2ea05de66dbeb662b03be726143228297345ec1a72a88bae9fe725ce4ce0177ebb53e6edcb5f321519412a40d035515a952d86d17aa167673a4c2515718489c1a07564500330ca037a3025fae2d6fedd43f46bb3680d6a5471fdff876bdc51aa71edfe91e97699205a5aa1d319d2be623037d8fd7996f9d4a95a9df6d3b8aaff2818ad3dd0aa1933e1ef6f9139a43dfb06ee5cfeb9ef3ce07ab0071c03341862e9de695e13c5c0f5514ab08bff1e223a706b66d60de59374f91d29502e23a4ec541bfcb026eef88df2960ae0a5073e0ab9e5e72f6587dce64b63eec8113f57852de4ec9744b39fbe2a1aa1b419ed49b935494c96c7dc027ca4e14e56fdce4ba3d7ff9d280538676f0ce1fbba5932a906c7bc2bb909c4868fe4875c581b211c002017d6d4f131034e62a3d5ac138481b72ad528ba7cdf86ac179fa034fedf8c57e7a81a67e9a3ee1d07a71c8329863b6a3f792d191fa647ccf85ce9ddc6e27c37ba5ba6eb6d256605bd124e09a90dc84fbbc8184c974d0d2a84d6ebc4d038c77d50cd08b2bd87416f0d4c5b8c3b8cfc2f3c2783f2bc938cdc2ce12de662ad0389e23c69923c64904561ca8c9e215bc04f5cf768b078ed207d8c8b75eb787233715a9a44a5090ab14075909d93ea84f5e57d00d13c74a070f7ba5089515415ebfe00a99f18164e3164eab5559afc782854a357cbbc5e357bb6f3c5ddd977a9d8a8f7bc930ef19e81c61e6d5efc51789f6b3b9a0543fcc8fe907474c7bf03ba32b2f2f1ea9d4d482afee7c7a88528b7e9cfefd6252fd1161a5c0331c3825703228c6fcf27c1e97b8cf368fb82cd56eab808e9e22a12bc88d14849a0fb6ef13c34a4a6a2a74f7fcdda0aa61f75452ed900ae7cad87d9bfbad9ded8e6fd3b2353d22faa438b0ef2103c28bf5d9d3227471832312326a76b4e78f5bcac055f84e89d76db5c30e0ad9abcbac2e10aa5f668f7de31dfdde4b96ce99bf6c901918db3cc82961be8022c302650daf10f3cc95362380052a49db4336106e1103c8482337267106b4107881698ee4fb4ff3163fac5fb47c76e9b3df8f4e88db8ee28ad58e367daac59d0fdd6577aa89ee84a370476b71dbb095f86a713b36f043b76cde3ab0283e6645e3e91d3f2efdef1831ce31629c63e2c7453597b9c67b6feffbc7d510878d2171edf8b871f6f68c13f3c778148fb3b71867e2f98c8dd3f4b3a846b8a8711f3ccee82a595f77e59d939e52ea93ab9ef962d0523312aa0059d6c640f23e2925ce998cb5a4022115078c88cce9d201436f28bd5108a2b1ae98d631d6b5bb8e674efdeea11583f5613b65d3f98f1a55c21c310f63f09e61e0f27c6f7d1d7d8f30aef3ce2b7f0fc627d7a917bfe3c5fffb05d3bb0ed4046f61fe9435bf8333a7fd26032c892014df23fac580d0c1930a8bbddc4679f1b1e441aaa607bdcf6548bf7716bf770ef8fb775e4878cbc5f727899309dea8d8f87f9f30fdb83ff4fa99f5d4d883ee18aee7ab8b33cd4d79c335c855e275ecfb7ec135f9e97b1a7c1151e33ce0fbd1be58f79f95ff9a3449a91f27e40f9b0a1521a9a0f8bd1ff0ce17f7854447e72c9fc3b4deb3bdbf276f7f9104c2818644db491229f0f64303f07b5f3d099f96bde94ef5aa39051b22b65207fc9255e738bd10429b5216366feec14d58c2d17b93051206b903077ac770df70e403c876b29d6eb632e27d2cdc6e3b89d41e390192830a901c689c9475b79ade66dbe0784d9f395eaadc4ef32b6b65cb88f7c40159d50e248437cc96633714cdd1339d5ff8d4f8e76fd59be3c9d247493545eea27c206084acb2a2fa1e929040f4272f1e4ee5f02ee0558074841400da06703cd340efef21f42dcda02dde7fc6cc5f6729d576ff63d79f3d59ffb63af46713f70b0749ce314ed46009f236cc467f8a74271539b8622a98e8fad87cf9bafda7efa3cfafbeefe70c5985f7874a880ef6629224b0af48a2639515b93fd3bc929b2e54246493a8b8dc8b9f5548240148ef1f48404c90a18262828eefc18ca8b85e465257d1f70367cde518c85d15df9957aaadd4b225f3bf5f7ba852ad738eeceb9e4fb546d57df75823b1627e93781f2697282378a657a2cc10f811f15ef95179cb8d1b95fae2df2f76795a334e4543370dde0aab0c49d0d20d9dbf8f9024997063fdb32a8f54b479cadb222a49fb8b09888fb3cb330089b0a31b300aa1ec71376cc9335b9ea85ca839d10bffbcf05b4d699b9fd4a676c719fa5566a5aed9bf7382a7d0464520a13eb648076d12a7076dd06411ef64cccca2003645c74904ffd2016dde2e990d82fcbdf3456a8fed0dd02b64ddb9b131b0d15d2c7419a0e7cb6924547163b9846a4f8cdbaed638830a4b753504936d510139b836ffb06ec22fe729f5e9c2e7c63eab0fbea29f374ddfbad50c8ce2059853ee6ba02420acb222b7533ae0c84d57a83ef860a2b4ed71e9dbe31b138e5cf433bdbf87f48a707eae7ac435801e909675836bb4af51b3f6a2330f8c435280d51fb3b999752675e103799ddae89be4a04d45812abf4d2f7a7fe53b9553b76ace7a5c8d8f073e3345cfd19b9b8ab7bc82f90848f7cd9cfa5cfc0e022d397a72df65151508728548d247f556e4c12f09b3efe0a27e9ee8033a825030be3ceff3e877ba8e739ae1b9cc796bbc8bbf9ef9ed2f33f5f63ee9c4abc2ba9f529cd2b9996bde962aa96405a5628c9a8d7734fb69602023e8c137e3f8efef76eb0acdbbeae73e0bc1e0708439158822b774b23d918d4fe476e3004d4a5db2c8ffde1e98b4fd5504845a9e01c4c971a0a1e8d3c68c37be6ffd76c3603797cbf2b1f3cffc5a4fd4fe9ddb4f6b7d8d52a91bd31a1e7c6d8267e52bb8e5527a73dab88263080a20923688eeb0310c807f44925adc496d1063d9ebca2cb01d0dd00b33a112a933b633402f281dfe94ed0c240c26a8b9e63e11a782036fdd0b2bce1f3f5e7fb6664f757da991de1c2f6fb9bd085e7b4c38289e000759710f4088f864ece500411190c61c31447be67ce9c001a1f26da802bc19181b3a0a9880647aff1e5aa2d48a090b3bfeae39bd8c9cc31f3a42738c29dfa674ce3cc883d360cdc0bdc99c43b24158d690d34560c474ae0b96a6ce993ef871a516749a346d16fc838880b29b33248a22230bc76c1d225e866d1aa492a29c4a24c9615e1d92348860900461a3df9bdfdddb643fa8d9de2e7b2a45c4f3d058699c873e7de730eecfc5effaefe545a5eb5c09a6ded0c68fcf3956a926630e1873c9ab985ff70bf873c7d9e8e79a3ef63d4b94017161858919d6b2fb4ad7ace9a0d46739cfddf736dc99652a1e628828ae83bf13314ce4cd86efcbaa404884acc222d5556feffc246f7bda0612d078e061f4a54d041b9c757b7480e88363cbaaf5376cb953a9af7f7b7d7aafdb35c77aceda7b5e772732a22274bfa7d9b00df44ea6834e6283c857d103dab910bafc885797bf1dbafd6ce0e92eee0b639c5e5dabe3b395085d39fa725cd9c2b621c6a96cdf389d78fc2adfeb971ed3edd2fc117ed18fe9f4b33de3b439aec43ce714e747f7205fd2744eedfc2ca586bcf5e4b12ee7557e4969334a0ee79338b07198632689438aee14e8465e56a40b26880d54253931aaa419d078dde27ab68190aa04ebcf3da88b9b6fea553a48a91f6f1fdcf08695fab719654dc68fdb06eed8f717b60c87be07e28fbc362227ecb541551e51b160cb1d4a4ddffccdb01fe0564b121707ea617ed87b4710661949ce8443d828a48ebd4ada88b2bd9079701b3022672149b3bd909f13a0d377e8bbd0381ff28e9fe6a13c2ed9e60ffb7e74d84c2d01977f5cf2c44f676cd39611463f823eed2fd3e7f5bf6d1b5fd9d8b2e3dca49f5faf7e7bc163e4464dde700fc4c6e5b6d280b204acaa123611b2f1c9f991f358fdf6574b20d4228921ab08f2d00787c91c838dbe9efaaa0595ebdcfb167d31eda9a9f594aafb75a3bb7f395f73108d1b3f78821bd1bec0ea5c3bcbf3cc0ce08a624bc0317824099fe49005afaba190689a52ea942491a8413608728bed847a1bac3a4b5a235a7036901c46727c0aa9a0308b4272c809901ca4089e2bb2c006e5e00af62e19eb1927249e67033dd20000800049444154caa3ca87ba1b66f26923af7976ad3e60af1c72f658f7ca91ce264ebb4e1b8674bc50a530c188338646fb58d7e44dc48483bc73c8ff9d4478e2446df4893050cc49508b18c01274d8db9792734813bc92f95b4a5cafa0351f2cbbed3bcdb1ef5fdaaef258cdf18756a76c6af140c267640077d8e0c6aea0dc5f6bc87622243de4e05af3e2d2b1a3f4fcfcfef2d46f669c6750920a8f732441a2209bc756a8b64a496585dfd96b8d5454940e9ceaa5d07c1600d2c12de6b7da12c68eb608609e80384f1cf1770e27a0f3260c988bbfebdf0fb832eb3e37f757bd48c3b6dddcacce4111e46cd3622fce0cf38c00491dfd8aec8affb9b68ed175deebf2689a3ec78e99f1d41f88df609514f601bba5cff3f6e93b9542526155ad34a2c3fbca2779d86a3bdbdf4402e11636806a4f578d07840e95bd2f28bf3d71a4ad0d242f91a20c7d20fdfbcb5bc7eeab0fa403078f3e671f2d994c58bbe01d3d7155232b07accc8c7b26710c4111ef170644bcdba8617ebada662deeea46bc3b594e17f42982381bf76db366368f5346bcb7445c697f6f847a825af10923de7db5e8af412df9b037925e2f3a1a97e3196740647ee59d95735c4e7c79f8b7b69f6a517b48a727b27a757175bddf1d3313077cf1b3800840db8a0379abd1faaba263007301efc6f51420380d1001826ee548b75520c2bc92ea7b50e01445e2eee046a29aea24b1502df5aa8f00c1f9961f65a04b10d79eb5aceb86054a7df7e2db9b2fefa5d4fa352b8e7a70a6be765ce5a7cbae49f010b94e6d451910bceb08dfabe2f48a6c37427bdac0af5f183e09cf072165c9830e28cc13a9a64ae877ec2bf26ea3e492151f1a58f92f406494a00c13d2bb67bb258b5dddc20670a09c5166b3719e22b8697dd0f94292ab1b883772c1ab678eeaa67f3bbaacdfa433a3fb26610479dc3e8d3e554690d33950d9a5a2b4d82d0075f382673fff4ca9a1673f7ddb9d13955a78c2d4cf0bb19e4b4cc873ccdb4d7abd615f9420854929e277caaec3f8b1ee99612209846c4f36607fff9455affd5d2410d9e88550471ad60ba584570ccd83036f12f2f776b061aa36eb491eb4e93d97822fda326dee143df16b2e583a6aa4a6f08df25a6eae5d5ba9f409355f3bf860cd096cb55a44d34147d8a869227fef0a8878efa9aec1184d2470402dee6dd43236c917a9667896157d5b2dd1a076322250f31149df097c5b4fd4aceec311efa62f22deadb7e9efe0847aa296791f964c2ec2fb7922dee3bca32ec2fdc668fe86ba0ff72170922d5634ce0ce051b82eda776654f67625855537169eeda6f11e7dfec0d00b6f6882317bf449938bdce8d8e2a94593cd2da5f06ba70d41b078898145308e93bb28110cf63a815b6f296c60954702526a121ce894a2c141ca0d07a938f88db6b751ce029258f03e9cc0330c084e922bc7e8755a5e5a3ada4de9535038337f9e269c4bface6efa8996c49aefdbfa81ba75f4fa1c5cf3b5435c770fcdc9227bf56a3c0b91ca58477db8f67cf47b6dbc66f5e73ff4556a5eebf133c693919b2295895060be8a6f01a448f25c5cf7878144402ae840fad9c02a404a5144df5eda1afe360de9cef97cb1013300c1a038b6ffbeaa82aa37dcefdca6d9d1fb86f4795173459dae5d5c964f4690d3faef09c983ec323817b6feb461c9af8d94faeaeb37521ed18469ca355f7d39493fb7b8ffe69fb69888320e842d39d4c0adc420cdf542fa7e25fbe0bec30d2c0781af4837d0976d370c4836a2016a079bb5a337eea1661b40eebe246a5af0b60941824a79c4c0d454c0470d4c433d87f4d30dac09d1ad065255d4d222e9be3533af6dd64ca943ea865b5ea245c17aa58d979fad3772e8b494468d1ac586e24b72689b842c7a81a060933517630dc78f3ace3bc6abf2e923543e03d0ef095584ed353afb8cd0d20d508948f21ccad66ac6b51d11ca89555159f0fe998bf0b970e271563c593e73fd7abde7862ca9fc5e733c13bffde2beafee556add172b6edd0486a092b2b5922449ba5be2f8c8dd561c783e9dbc4c578d03af02aa1ae6bc84ad43eacaf980dfd9063cec9e1e31209403089543da1106a6c206920e5d37adcb1ac8fd54e309a5da1d7542d7767f2a95f951c70e376a0258ebd8ba634f7d34faac309543c0b3c3e6d9e6e985f7fc7ac7f35ab298d26944d308c6c1b643d88e8a88a3c5a147d97437dd81eb288219f3cbba7472772677580ca1fa69c0ff5e8dbd3ce93be1fba588f3c44da514ae77e9afffd292579b4b8e29ffa98bf265809049294b4ed9faeb6fcd959a3f67e2ad6e4dfe9fed2ffe37f37c838f032729ee4dda38608ba11c63ec05777c62c8650828be895457e40587f54e8cf6ceaffbbfab04422d02980748bae602c00cc031dedb7c015e8bbdd7b9c9efa2504b365b2b364c2bba58a9c54533c64ed3a2e4c24953d33fd194bfc63575be993f5f2f9aaf6b2d4e75bdbbaad2fa367373f9740bbdef12262b56f02a7aa0ca5adc49dd6c65c47bb6a8a827d377e724cbbaeaf54f8fab999d386d7d6c9c1918675e140645bc537a78789b390f54ce710f9c4d9bd67ce88af4f39f9db4e103cd517ddbeeed7fbf5da5d46f23274d706d50c5f3b78c22b75b3606524a05e45422d19b75b9e455026f124ea141de2564cc953a7910204a26c77106bb9b70502bf0e225ee9374ee1671a739e2f964d4cc0324ce30434bcc2b962e700b282d7c79f2f831eef8dba84b7fd0eb719f679a5c72e0937a5dfe9036bba5cb2815eaa767c6b0cea933aeebeb5a32db327cdda68d4836c8f34e11cba433271d3ba57ea182437410891421aca2c230399ec29613b297b488b7cb2c19be1f7d4797d014b69f7dc9a61795ea58e7f4f3720bf48fedd40375bac6f65fc9595bef9bac25d0df474c1bdc5f9f2f5ffcf6e2b9eef42c1b38ffee15a4faa3c03fcae54569efc93984e26bc0301161a78c00e49e5b2ee23b2a64ca161161ee0b8c2d48381bdbd1feee12886c1103e23f6814e2779248429048524e319038bd347cb0741c3c35e07e980e512f1d1c60da63dedfd3c66b1cb7a53f525373846daee8d4b1dd4aa59a6f6d5d7292e66c6bf5ae5bd1467368e967d6ce3d584b2e2993537aed333d36aa6a4b0e739062b22724073b201ea08f90246cafe42025891d4d0f5f59a762999b5caf7c63c9d9cbaf576a73cd75bfcc7b4d6fa06eb38e9a3849138c777e3e72d122b75a5fc585c499929fbf2f771179d151d237923c90f48db2e6b22421385ff23e61ef128a3778d00b2b4d3a4acef2bcc70847508b18c0ebf566035390543024d667eaa906b2e44ceb1212740d482ae990506a6e56aad5c8c31ecc385ac38687f4f9b726dcb5ebd5df98b55aa95187bcdae83170d0243190ff3f49763eef35106e8eb301072c250ff66e0c1b1058437b2f6b7c9ea0cf1a0e30daa9a719983e41a92b3eed3bb34f58cfc5a4cacb5c82baa4e79cab7fd0d78f3b20ff8e25b061d1f723092605f888a160db2e24058ec711927711050eca887eec2319cfe4abef21bc0b77ddf7dadb0808b5880124724a5581057745df02000746aaaef4cf0de40dfb98b7cff0746f5f6ef45470c6295a826970e2bee3ea7753aad1c21637367e45e33ca3d6e3759ed6b071cdc1aecd25f5fbf4776b3ea52f1e6ff572c76b7550b746399d4354dba859f432abab7551ec552963b16e207fea32ef64982bace1dc37ff759f32cba8b3155d8ed665e63e67ae7393bb80ca37960e71dd5dcb528abbbbbaefd2014583dc0364cdf5cb2e5ff789521b5baecad82a74da94fe9923834564af8f7090682e52d33001211d3b1112e2a888609ce8859cb2a2b3173fe73a42dd0e075e447f19e1902d6200a9b6422028ccf08090f03ac5fa4c23c687080741acbb1ab0f1a4c3af3f158c133150d4e8fbc814179cda0384830f2c541094f3cd1c2d4920d20d746f6fb601fc9d08d2f7014c032171558c513801f04903ebd4c175743ee07b90ea9d244e522d717c0649e8c438a14fce419260f07d54d783548b58f755c22964d713fabd9580508b182009090770914e9308c9615e980aa3136f5810102610c419c21b2c6dbcb89e16c8a780500d50adec9493bdcf67db4d8e183771a8648cede07bd33ddb8840d8807410531d1778b3c46735755ba5486227e377e401560e6f114ea34e816de5debe8c33e09c5522c29973fc8401ff6ac2211b9531803157ae4f863f1ac89209ad37b10e99a010a7fb88170fad2b960c313fe542d7cec91331efacc292849a525e8481f71f2279700b1bc03657fcecfb2ec4809e2e20be43ad5ab88e248f142f5e22bc559280906a8b54b4987fb271c81c60fc5dc8c64784ddf1becfeeb34da5ee6a847bb8850d70002deadb06b20a031bd5c142a882c4e0c0cba10a1fb8121f9c3e7c05e627053ac854b88fb24a8c080844fe14480129901a52f03b4b4404a9c200f02ae0b5268b7e8edaa38d0f5c8ccbc1387cb98928fd33057ade893ede9b0f7ae26045c05605d5c87e0f7d72b3edec85952778f155e17747a8529c30a074c70d277ccdbfaed1b84c121d5515419fd627cd33b95b82e1a0f5c9f34db5ac6104a7832705de3accb0a02f8da7155059955344f9d180142f83038c395a1c74be38193bc13beecd2d6200c789d0814f8498246e3a1fb01e2d48060ae7818244920a15217f0fc22308884c1e4b92067de732b87f57e2fb5491c41110b0b9fb0907b5bd5d02912d6c803701b38a25b9830eda221db4e0fc885320af2e3af049224911a26c2a9449a4db4cbd15fd1f12e36742421208cdff58316e15f01ebbba450ce085269a2f8218aa21592783d36dcbfa0d32bbb2c87e5b3113f0bfdeeb181f491a528516c469ed2d075bd800e9ad25555c969464c9b607c2429c700a189a1470c8b46e99e31591d8940edd2721922e9e0e2a996c0fe3fec7491eb2850d604984f62bbe0b7d8f14712e30630915177d0fb68111a3400484f60b7d0f620cc43e621522ed071167238de37bce1b6e6f9740648b18c0eb1b134c924915fcf45955441f000739492895d8a02910f52b2142a6c08d2e04513f85206d6c10a0907033e603812412aac468893ec511900d049ca1daa2764f23fc22e7933c881d3c9fbc6d48b75a0509c58db78942704a7cf0904a8b36c828f13b119883c47d64fcc30672285755588c8fc6bbb7e9e2230638610359720624826991bb2511568af8a66478a8049882f52955a5167e575049b16e1c2a2b2e814a121d491cf83bcfab7003dd6be679475bc4009644b07fc98b939d08305f0adfc3c139e040b2e3ef019b8682ad89093a9c45f87b200ea70ae70a13187c47a74a3c5fdaf8a497d56e6fff3402225bd800aaf5ab1090a668e32020870eee2a3ad049e70ee36e08128b850867f2e70f81530b216297bc6bacb3c47d504d8540182c04c4b1044204060190aa55d237db3ded2a2f245520135ad88eaa28e00a91d75517a08f886cb6912010902280abe0865d05c25c85646f74305204b783bfb304d45d8c8772544112dadbe20eb8450ce0f5490736a93a6c40bca745019158375520ec15f062e3f586804cb6a521a2994a94b21304d9b41aa28fefc811fa34aede025fbeb76fd1efddd5ded9f03e5c039c20924a2a042ad33aacc2fb32e389b80e0bb63c5215f2bc50013cda0fcf7a9f47dfc181130947f45366030a80a5d2ca14584deb251cfc6abbb7fdd3090835923810c8c6120a1d40c268cc111644f1b1404254a43e823eb295b24a0cbae310227759f4c586b6f6f1f65975015b8005dd342db4bfac8150d2c1c32a2c44ca3acb00893382379583dad3cc61e1c0639d3e7170c4e92215066f20da50b6f7b9ccf1ae12e39c539d97d90b1abd876d00af4ffa0f312f746054e180b3d60082f072f4f379e2394845e280602892ec40c09930930414c1dfc1f8d07ae7030b0c183340bb5be5ba9b9a430cdd50f13b1110aa4bd453dc88f7ad0aa3ff27fab061f077682beea3752f55502471df0848eb9fbe3fe2d75456c2d7f80bda3fcd06b2b32d62007f781b7dd2855adebf87a81f4a7c1dd93aa48d435ec73a57e2ec68c1ee6123ba6cbe5c4680b2029f34daf1df49f5618bdf855717a5a2f1d95c8274bb76c038edc057f967b48801bc2e88e3c7c1266d68bcaee43a0a27c61bf8f7b0c06f0bbcd4efa312b748c038f65093ebd4f777a9b2a5835dda12e8ba1cef7581f31b09788e7cbe7c0e8d23c9b8fffaf6ff8b0492acd906c885604963b72d206d1821babb3aed86afeeb74fe854a58e79ec8cad75ce56aac9432d3bee73ae52b50bebdd55e75a4d5c5aa62c8e1ad95e77d2d4f59a6b79d3f9dc72259d03f4fd86e3eb15e55c56eb63d88ec30d4700759b35573c759ea77bba7a31faeb8b94e1c7fcdd5ac8d79bfbc9b1e0e618e668ffead0b7ee73ad5be80a15e59cac2f4365d1837d95bacf95204a5a16854ade556a43fecabe9bef506af2daaf9f7253962cf978eebc0a18731dd8867c2534c92b8e6c1e82c028499068e30a6f1696182defef7bad6a2ba8850d600905ebce92bf538b00ca830bd7cb1441ded05215637c88513a3576dff1cf743ba2865e59077538eccb7afb2a556765fdd13517b96aafaab91e4276b1732dd5d97055b34e4b6768743ddfa6c0675bd138796b8142bcbc65e4dc5e588737a1aff8efbfc5bf8a55687e2fdfafec4cd7bd7bc584df5fdbfca552e353beb8329a2961e1daf57c109fe69d176654e81c0474e065c5eb16467207c673ae8d4ff3d4c7fb3bafdf20afa8b04ad898c0fce5aaa9eab6ff5f2510da7824b286016dfc2e378e15fbfd3ceb9661753541c8fad709bf759dacd75c4afab747eb051bea9ff2d8e1b7ea6bda85de6ef387eebf199ad8c20d5cb454dfa85153e696c253e372e750295b332a99bb4a449cc7e1c3a8ab9d0bcb06be1ce08b005f0ef045043e1bbd20fed2db7e503fb85e3d55af55951716ba2e8f95df2db84ca9d29e45ddbed71bf9f73b674e1b79b75279231ece5f4a2a32d2bd1361116ea7acfaa2be9080b84fa27d77efdffffe1b71275b18d03680d76f90244d90eed7fd6b073e795c132d11b6fcad4df7cbf4ba0df54abdaffd0d1a8e0f75683b58c39b42b96d96b96a1c6b79e368a4bf35c60d70d4abc53c2556d1b20f9e6146c5b9d7c4bab2d1ef233224d8de0a7efa5f83bf8fafefc527332e387a5968c6c4395b9db3e5680d5fad4a29cc74d54b1583172c50aae2ea8aeb16bca9d4cae282db3fdfa8d41ba3ee9ee7964c2e1eb7e54d760f172a26b91e7deb8f246e257ecff6e2f349d461b597b6ffdf0808057291712b82be543de925fadf55cfddbaef6b4a35bd63ff79975ca209c592d48fcf9be94a25a1f1c70c77f977ab221a21dc412e6c2f7f973449219a950fdfb08b387715369e0f9f02be08f07937640ef7e7603c1d802f022c1e3e3330d58a4c918292b51a5ff5084950d31bdbe5b02a4696771fa30ffa0d9fad9efdde337a037f78d7a4e123945a73c31fe754483752f2d6a20d4c8183bd459f8cbfa4331692c83f4e32b10d88cbf86afac4f044445fc3bbde7cf78dc30ed392f0c6fa4f5caa097b4af394a74fd39cb9f57ba8c6a1435d75acd5075e5c8610f8bf7bd8e016a97682d6ab95842149ca580510a25dc5f0a039eb9c27d7eaf7aff8b1ecc2715a02d9dc6ebdfd4547a53ebff895ab467dadd4ac93c73d568cf828197f210b8871802b412240d2fddc06c41bec7debf39f4e40c206f0d224c98308c9c54ad56dd3e04bd76ffee606afdc75c64f4aa57d5ef38a1b87e88d7549e8a6d3ddc8f453acb1513f7b5ae8b69018628423d9c11fc67d3646b3472486c05c5882d3f3718e010470473768b2567955e569f335c15e75d992268fe979eff7758f15a3e00ee9cbf143fef244382820eb65031d383b54495d7618fdbd5d32891840465d5ecf7184e2922beefdb46e5da55abf78e491572f8d265d2cca6da599a3f3436f1cea26b16482c0c93e693d58e887d10f627c4cdf7fd01b7cb1c264169ee2c1c77d99955ae480f311b01dcd26bd83cdc972c66efa424bd02d8b370fbb5da9826b66a5bf71b9667826ddfdf81ca485e7754801b314f84a714b24d190242d55b6c2b6e7b3e94576e60d7667fba712908801be1427cd946a92d3b224454b14d77ef2d4c8f3ffa509c62b356add73affe5be75051c78edba12aa2e4871d5073dcc6c1df67070ffe7c98d02fe23a1c11735da0c460035fe2833f1f7fbf88379e8dbf6e2f2769eecb0781bc08efb98b3668502bbfacece1896728b5f8fa5f8f7f3455a9d786ddf1d464533d3d963c6eb4e8534022a9c468a312874884c3c6efb451c3bb7efcbbb4850d905e4e1679611da2d4559ff57dbc4103a50e98d86ed04d599a607c98fae9ad6ee5bcabad798d676d839190ebcbf2fa545583f1d9397cbc7eab8dbfba8484f027dc6f3bdc5cd5983ef8cb524be67eadcf8d82b1b39bbd709e5e9f9fde71e1346495e688fe208687080af5a5ad4f12149f71ebefd252feea01eca21636804b8912cc34d05549ddf29ffedf645eadd48925e71dffec417a832d4febf7886b2cfbb7b5a079f3b8859821544516a735370b310f7fa1c24d362c297d50f64a9686f5951a1584240fcfedaaea98ebf0774b6c1c2a8599419c19927767066ca0ae286d4b7d4b96c6c5719421383fcc597464f1e3eecaf8bbe33d88c02acfbc64c630ec4c4bf9352567ff2b946a5cd062f9a5f3943a36e5ac4eee86fab1eba7fb4cd31cb433c35948df990237991050c1201a4944f40bc4ef79e2f7825df106bba0d906706967eaebf768f8e4bea342b728d5ebcbb786e4dea954a3b1cd6b7d76ae9e8bd2948e679fad5c9373ddda37c57d97d8411cc5a2bf5e0f6033fd08fa19fcdd33cc7d62fd5329d70c71d05b027f21f0c54a387bf031639519b0bf72846a3693f1e761fc1918ffb6c71b542f6747d7a9e56ae5f4fa74529bb63e4dafcf035ad4bee24da5b29b77ef79f0294a8d9ef9e19bdf2070308400d910dcf42939236708a09185f1bb0d18f1fe9dbf3faefbdbaccfbd9e80840d084c09a1e11d33dfbdafb3e654eb5cdfe0eee1ada21b605ce793a20bc9f0b3969018620b3d8267781762064b20c6d9f622e6e423c0e73df8f37c12430f8cd13c9708d61cfcbd13fe4ea27b266d742131f410124321e333ef910fefabaee63d59b2caf4a9206ce0cbf08cbb5010c07cd411e96af5c3dd1909e7656737a86c6e253e8db9e69175da9cd852a9cef75e30a8ed754a2dfa78e6033f0c526ac386d55f539d0acae1c592751e600ee3327fcef3f6a5fbe45f5e492f62001f1c790684f44a68f7c1b193dc142657edd337edf5e7dc3203a9a7f72ed07f6c667d56c7b576c56ae0dbd19b32a85e4c1023216aec5b98bd0ca1eacc14eb97189f1c5ccf12297f77c2efc5470c490fb91f02c6dbc3871ffd80751a63d4c47859f58afd45e3e78af63bd6ac284e95ba5f7a797b2df9e5fcef92ff1e778f52f54e6e3479da614acd1b3671e566646ab010c82cbd3bb9767e2efa79e8033221e983df6dc0c84e8d7c17b4d05f3d801d6c949204594de9bc706d19b73df2c6191d224add97f9e1d0f73fd007cf05b53ff9de55750c745e77bda29c5ecad41e478deeb85ae261f33b6a18a3c6b4fe48a6e6346a8aab21a8817c3a6aa2f752de5ae8ed4d9f6b8ca346b5ea8d38d608d730bf49e0cbc275a8796daee71ae543ccf50ed76a1735d01df47be33dbaa3e42ee313b5cb8770adf230f0f5f68cdbc17b50adedee2a2b1ebf9e97dede7911f340b5d667735cef2e69b5dfadfbfad95395ea79cc8ba3bfd51cf74dfd5f38edac2bf137e41eaa81ca93e95f1898b6dec054144c0a217b72086e99e4c0cca49502fbf6df9523df46cbf23e979d3a9a29d5e681a36e4bd59cedddbf0ebaf1c2214a5d70e8ed874cd5479e7556e8f91e4be2d703d5e446dfc1fa89d5d837eb275663ff265c87f5c9b5ec69bd9aef68cb9adf8caf3fae33d747047ec2d75eaca3a0f112fe64e395fb4baed370d078057e1bfbaf373b39ef92759a3ebf66a9cbb076ce38effed18d94ead3e1d3d7fbeaef9873f1251f1c8075596ba28135871958a38b81692d0d4c81a332650de7dc667806c78bd13afdcb020bf73209842936118eba0686f446baabf3c0963d0af4c7685efbae2f57eabfadb5aa5c6f1375b6becd3d286e47edf02755cde84d61d82ea68063a2f4003670f7e1eac6d1bfe88f66fa5df1f96e578703df6ce03335c5fb015327d442b7717d0c5f07e0335503baa27f3bfa7d703dd556ef072f2aa8b814d56a1fc9e30e47fb11f4495ee9ae4c65e5662cf866e2b961e0234e54011fbd6d27e06b0a7c9d80af03f0d14c29efbc900a0ff78fc47bc4f0992765ee24c787163a2074627d2d8934fa7ebfaa73de53aac1a9cd668fd75f76f6e4f1456bb04e426464a6f5b22f6e46640c4b1a1429938b3ebd214936f9bb62c4095a18cf856d87eac0b892c6058d6fcfa8a3bfd0491f759f32448f2ff58dd49ef7df161d5b8b669ae0591fd17a404dee91b09da146b75ec7a8814f5e785091d27aea84fb6df45932c177cba4f5eaabf94df88a701df934d6c175a6df83d79b771d058cd742cd7e9564bc8c8ff717fa7d766cbc711611acd35d23415b2badba692ddc9a2db59a1c75a6526df38f742e7d4da903b6b6fdcf2f8d959aee7c3ff44f387db0aa8b522b916deb1903391b32358a8807c9f3852314ecccc8b7a7ed25048408076f383a2034a776d71b03e7dfad45c69473d256bfb0c188e42197f796222de9fc5192551f70fd8035c35c87855318647b80086c4304865fbaa6fe51c1d29ae253e598bff7205d3089f401b6873e166aabab6812ee043699305e7eac075f4c34cff08c7b2497ae9d82f708c7bf07eb8c7d3699009df94861dc97aa03a9ea504215219d120a770d2189aab8f4939a3cdb6245a69eb9d1151fce1b0e0e8f0f875cc0020302dd7bdf15b8a9985707effd3bddc20648d5ab9bb9e0aafe8f0c6c74817eadfa873c3a7cb3be666668f529efab7895615ef4e22c43f6f4d73d241e2b3312f4bda5b139f6fd73cd75acea01fe242a2e52a15a02bf5c5f36f0fb55509909c72b55b201ebdfa95fd5c4ad1d5ef665c95b6b3421dd7adba6d396680e7d53ceda110bde50aa746151e3959a23af9c59317bcb1dfafa6b9c196e6126eb736b7ff7bcb06aa70c4cff207a86e446d747d88c6fb7a9b8d0ace3ad9a35ced0f4f2f203569ca319df36fd8f7c60712ba5263f3beaad82025c43e75c8617fab265cb759a8bfb07a21f062cd8f9716fbb59bbfb013bd96c037c711a2ee1683af0bc871f76a58fd4c60f3d1ce5b448b318c1bfa69fc307bf39e8fbf8bc3f22789ab91eb6072b99df3b0e7e2b76f00fc558c39e5163215a7d026c0ffeb88d2077601bff9a71260ba4ea6e3849cd9d780f7ee115e6ccaabaccdd90eb87fe79c8cc864aadbdffcfe68bae526acda0a5c3ff68add4ea17ffe8b57a8de6a41eaaf9a4ab02aa734b83a1b58f566affd7db4e3ee86a7d70dfd8b2fdbf062bb54fc3c60ddbb5d3dfa379ca996ec9d5a4de31dde1b63c5446d4ef5c5b76c182579fd1b2e673adaefbf89dc5e637aeb8478593088a8a87be825522f7d04e7bc3000fbf71c4009770fcdfd17d521bbea454cb21ad7f1ddd595ff366e8f9c30e57c1713a63b15ec25c02d936d761ddc6d6b19721925e81e85b7d183fed8b6daed7eac61559b140432f0321f1c7dc7573dcacb745ef6f6a5ea80fc4e55f2e7a69b2e6c47f7de98733a6d6536aca41dfdc5290a7bfc5ad55abd84d5606f8496fa6480c663cd861647d2d9b1fd7bbdb7f0e5fa754bb538efefc0c2db9d679b941fdb6cbf5b778c03a3e5a386a17bb03fbda58d5d775fb5d7cc3ac7e776e51eae5336f3eea8b4de64fa5a2a433ad5b99769f0b49492fae3de65df87725206103a4ea216a146ff2ced737acd422fd41e9435efe4599051de524e48296073f1f5c66830c95077000a71cecf76e8e83ee4680d4ff7a321225c087bf061efc7410903b305ae28da982dc13e5b8c5bc946e28deb24673d4f3ea4c0c0dd784e0fbe683bff9596fa0d5d72f7d6333158612f53d387d3b6a8d5396504a6fedb6167d5bd7ab7b8e52e7bcf2df3f4f3f5da956cb3bac38ab9652e9e7d6287439eaa407e02edaa0ce994e5d371071d8b503be385faf8fb1e3f31f5908555409d2c9134129439c0913124adf4f8404f1249c057567736e897202ae31f5dc26b74c724b1db71b74ecac51c7baf310fae9c48a040c90747725c9776e124662bbddc1b7bdbeaa1b572423c683189f8ac165cf6dbc4da985d7ce58f055b152931e1ff1cdc4a795fa6df5d4f6ab90ec4406e8518132ae8f416eda14f7438444e654132d9e31dd2f2da37bdd7e4a759df7df534f0e6909e19e8ebf5ca8bf7bdaf1351a377a396e3e6cf1fe3bd99cb39c7a6e05ced923279c7ce3c74abd73fb031b23f81b5522a4daf55cd256961afecb08c9df558595678075b58121bdb16ebbf9cd87ceeba53fe8313526bcfd968abaf5b97f67cec812aaa23c293140273b4091c410d589c689dede833f99aa882410c6b773aa22bd308d57978c1cdf5e5591e58d1c77d63ac32af5425bb4f59716233447fd66e3bbafed7fb752d3fb8c3ee237bd708bbedc34b518151a99c381f1984bcca25f8eaaec1528454b2537ddeb378f5957563c52a9a95bbf7d7c96e6a826ffe7ebefbed2a4b0ed9d47ffeaa67ea997d6e08ab6e3310f99712a8e4ce1d5b593eec0d642abcc5561367ffee04f9b0cd704e48921bf4532ccdf9c568057011600ca248f74e05056541c48568f1d1991f2d999dcecb919a587eeefd68fc97eb1fb231fd5d0bffdc76a71da872ace6b891816cc03ab8cb08e07324364bebf543d92043250ee0be0cf11f8c672df327d1fe1b0d1033ee10e2cc7db83fbe6793d0cbeaaa72af34a4a94fafd8c19ab877da1d4bbff7d70547f2d234fbef8ab4db3f58e5c5bb4a2ffe697cc83b9c4eb5b80587f65afa30fa373199548461d8d72147a2ba3f5faa0171fc337013521da52b5614e895eafd35f1a3d7cde7e9a905df8d58523f4789a576436700309eb7769bae4e0befa2cda907242ad1be3e62373e70889b5c02a73d741d34ff77ff5d4a57a9fdcd430ebe71b949afbddcf43d7ac35d7500550525d39229e890904fd9e011801cc15fd5dd6fe6e1248c400aee075b35237747b3ebfcd377a6237363a61d299fac7bbadd16e52c26d04fc4989c136d7414240dc86255545317c36ee4ec68199fbbb5b9068a80c545289c106be3eb8cef31ebe1c41313ffd3e786ed833ee0055515593aacfcaba2935eadc7787f4bb47a909977d3e7c3e361e979a254e9b2ad1d1ef540f850a3f550a48e9d9856e96393a8c9c0b6dfda8d48513ee687d8216cd8f59dae53f7777d2bf2d4d9d58bb9f0a5425ee74c4fb18157109c1f7bd06e75ead8fb8e127bf9e311df51a88a32b46019f12a4d12f433d06aa155e81b4e795548f4170b6d59644220690249d728896a47f7a77c8bd5a024a599f7afc238f6c53d20d9b5f452068966138b4bc9a4cf235f8aa8d9fefc377f1ae2f9f4a96f0fb23c84dbf8feeeb795bfee7c21a63341c76efab5b3f5daffb072e6cbcfe7083992bf15124b7286d2cd723d50ce7f54b017bb2467eb28c0311037c9549e3d66d14ea03bec109cd9ad49ea8d4d5573e3ae1cac54ab5dcd26659f7598a3520bb4a82aea85f3ee68f3fb424b2f48153bacf566a9e3de9df2b5698bf95922a966aa6a3e473b9a8f4292b17d2fbeffa54297f17021236800f20fdff13979edf387d9852c7adec963e417314d69fd6931d37051f983e559114356163d0c73d490c73e39f99f4e0f7e3b381af0ff04580af7a07bf24803652a3f44132c5edddf842b73de3a631cdf2ee52ea93c6cfdd3b1aaa18b92159c280ae953938ba4e88ca95e00cf94015aa81f8f89b28c406e492c07a639ef5cd75271fae0f9070db8b173ea32593d0d050abf474153bb0923306dbd5b65ebfe9a969cf2af550dd6e5fdd081b4411fc758aef01446d71d2359752adf0190656a07ec3769776b50de075ad19a2ff1df97a8dec0b94aa19aab5e05b577576b26523550e1152dcc5eb2c12fd5dda32068070f4c43af6ad273ee83df892aab8c2162490c07d66630e128e57e29f7ac2b757bff186261ca7f55f376e9cb9900e7c5e8fb40e2149706df072efdfe977b20d708964590a99321088e49c7c70d29b813521776e82b2c22895aaa512c22ebca2cb83a373f4fd879f9c73c15dc7e87b4f0dadaf556bd71192ad6f6dec3646afaf87e69cbbe946d42d625b1e6c24bc4e69de683ea87225a9fe0252faec7cfb9ba8b0d8cfc136c03d80ce2feca52ef9440ff1fd94e76f724bae5ae200cef32de88ce8ef41816d8510e46c480c0385aa282f89c420039cc83bc5a72a403f2f89c4205566851489ee8bf40e1b7c811c690ef045c7bdbed39fb9bf36d21ccca2fb8ffad02deeff917ab13cddcc2b198bcbc169978283296d6e600912c2970212675e8af8891294462dbd1678a02220dd6c192a0c92caabe20a402ac1aa39a30583a62d5ef9b352878ee8bcb4566da5eaded1b0ede1876f635ee43c14729855a6aa464b9f5aa37373fd9e15b795678ed7846cf107bf46d6a1146c15545a6484ad5a642097ee251b086ac13b19401a01b4459f9a19b92710f09c277afe5a477fd97d7bb71a35da55c9acb316357851c5af337a2fb96e131ff4d99040a6601dcb08f2c21d8c201f8bb7f207d6e6e19dcdfd03b71d41be6ac592d1131e53eafd5bfb8efd0405ca985090ea098480243eb249955c6a2011f492fd005f33b018925ce9ebdeeb48b55586380a7696c0f398415ae01d47051dc02875c00c962050f112f82fbffff0de6237a5c980e2d77f7a422fc68f0f7dc7cdca9d7246ea0d510dc94e7a19a61f59f3d24c4dca67341d73d5fb7add6efd65e3c072a8dc58d5da4af4096600c2898409461e60c1ce8c2cbefdd504c436c08224c4a947b42879e2fee79dfb8a1bc179acbafe40d7b81b5be019d18b3244aa0d69632814077f3efce357b3ea2a027c7400dbc0670881d4394b5b493e0efad56a35aeeb0e7c99786ed8e0f3b93ddac0e77d8f58a4f714e033f7c7085806f0e5019fe760a9a85976ece62395fae0fc479feba739fb4d83d7debc152572cb5a0362a3968280d0c62cc5c62cc1062e25633371e42030c4f1947d0e482234085305e99c4972a11c5504e3921f6e18b47aeba29a9a839b179e79be6b343e3e5437bdad4ae40e6ae62933e080ada6ada466699d92f5d395faf9cbe1c3676ec43840302a1188286bb257de803e15bea20d2b39b93cf130f4793deb1575d629d72fb84413e6d0b89443aecc56c111d362ddb2243110fa8230f74d1c43f700062876d0db1815182069cba075c6712079e87b18131e6fe1b619acdf3bcd48fd5c33046f1f73ffddefbb9cfbbbaa8a0f6c405a37ec6d4484830806312eb42e014bc1c0903344d97c014108ca6003619b1d313242455bf196f89d246d6133a93c0050a8ca5cdb44e1cb733e5fffa9668cde9fb6efb7fabee346749d77c5026518da4cb5d336bdd677776ce1aa84c7f7fbfc9529887be375482a557272c13a261b1fdb4cc2e2f70cc0c88e8c28befd5591e8941597bc5222068634cf7ecb3bafaebee61cdd39441d7ae227d1c931db35e2845de0b447e4e810f4c3c647c6b91011d14191b8dd9d6b70dd71c087c8718af4c6f5b148effe5e7c88aced8dc86fc493687ca79bebccf5848fc6ed0445bc3b1cf11e06be2ef1f835368a1c0f035f6fe0a37930be4139ceab6e65bfc8531f7dfaca10a59655fd36721d365cd9930612612846a9dc22d468dfbad5c0cd58685bde411f46bb2dc3011168b7159ce1d677bdf713a1da32d97bfd162cf42d5bfdf8e776fdf9a56573f4c61b3cf5babeb7e81f5f71aadcc0285f44bdcd11efd17e60c4fb52fdbf6db4fdfe9571f0197a83d568576b582dc477d4a801888324fd7103d31e3530a591811c094c56ae382faa68a38262367e27abc4214a9ddae4caffd63c4ae3b825f58ffb3b2ace701018312dd6adb20322b29109212ee3c185b8cfec83ee02ff106f4436e3ef2ff1f3bef0e08bed0bef3eab6a52f953e5794acd6c1ab9e25dfd5ddfefdab7db276ea4ff494e791924d3122419245521af3fac9bcd38f868dd31440a90cd20f4bc4eefc2fd19c057e4c55bdc03f019ef7319c206567437200ee6a25c2fdead5827bc9eef0c1eef9203e70efb73b452f35e987865ef889ea78bab3e2b3d28b65f7734e27ddf9456196eaeb32bda3f38258cdf6ae3b9357f3790322ea483b14b23953145b2938d87322e5060ec4ed7b0ffab24102ad94a91e4fa052f19727faba65b94aadfbfe9db23dc83a797ba3bfd9aa8aed71b28950f01ac2b07ce450f6e6b2422519b627a6c4496f6c176ce52e746fb03ac6bcc7588d4a52cb85d832265a122202fae3ee03bb3a0721a600e7e7dd56a8ccf5c5f2802b2a67823c735be02e0cb00be289f630dc5676d2a22c70bf1dea4aa9b622270d71cf3c7d953f2941a3af4d99787c36ba87c8281a53f195832c8c06214f72fc6bc17a3c6753172f41443075cbacc40524995d507bcc340e6d848558583b61235b82b7f01444d743676fe6c60552dc0364a4d2b1cfde6224d584e9a77fe39c7acd28b7f6cfa99fbbb78fb307f5f807930f31414f17e9c8a92376b0d6f0f0fc797b23c35a59eded035fad61ee79efff35e9af8c3f20f310e4818aca280a4547996b7cf7121385898a32386080717b99f87862a754ef39e993df503439d530a2e7b38ba5e282ec7acb37e14318d754a190d060644785304f9ed58c773185f7fdc47fbc01b91ddd51b91cdf89bfaf09bbfe71b7c7add25de174d745f73c0d30b472f786ba652c3faf69f301611d5a412225512312ec590208a0ff1fe5e04425c82f92b012b504292c5fb80b42ec90b0b35ded9f9e348032bc138f13a942a28591e0011e19535c5fd483d52b9c97b3d49a695641b834dd075739fb6e9bb977ed7077cd32d07b499afc7bb5f8dccbbbbb859a2af52ff87837cbb22dead19d6b2d0251a5fc3fd5b1ca925e79fbf1f71f5679ad1297bbcf8d5ca2fcd35ce99804f611c2499d40624f7deb3bcd0ba7b5b4fae4edbd304c43680371a168e1bca9fd3e3f2c9f71c1755651c78ca23d183c190194add413add0c615c1ce8335a1bec8542053505a276368c7f6b025505f4414d9f5450854205350509304817bd06c748863062c6540819c097077c5eddf6148e1cef67ded7abe28a534944802fda9fdce2ab8f3fd01c73c1c8598bc95b83dc134bf17dc958cc711001360ef23b972a804a703a643cafc2c265ff7bf27e81ce9503bbe877481eec3e4b07af79b368ca86c337872fafa3dfbc5eed866961330f799887c4aa14a9fa198803b829ab6acc3cc90dda4ebdb55a4b6a135f1ab1744643f17e7440e0e0280701a434f1bef78384c549ee32d01fa8d4c92bfe2fada626e8cd171c74f4604dd0adc5eae87a87a96da83aa5bbae2fc27b2cae33fd42a4e6b0814faab8f2808fddd871ff40815fd812797d06a9b8b02ffef8e8b795df2ed082cd374fbf341c3c35db384855059569111815b661d07aa4f507e330a9b0c81b8e6d16a42225a3bb5425617d914a92fa52e5e88364337857dc87dfd918bfd8db27b75a5621d1df81d73dd77eadfcf197657a5f1e9a7ed2bdeedfebdedaf0944ecd12a8d6e97b2649f1136a98b2c1adefd2b269ebc6abb5a435a5ff372fcdc7bef515b27a578c5fb8fffa9c3f720123db1a41c2516def0d3bd9c280b601aeede3d497af3aa3f624371a37e5b29b5ca138623e2f275b8b18ef662dda9bbbc7c0dbd9367d279b974314ab1619b3715dc4dccff8cc53f3595560fa6370bd6dae8fe1431f2a288daf37f099e75e88b0b07c88fa0e9e3706d793ea25dba1b71e037cdef788e1ebeee93bf8fb185c6fe37ee0734ead3add354a4fedf1ed01bf81d3abc482218e8c3620e998894094d2c6a5dfb171c9b8eef3d612de32e4e5213939f93b491ed2ab860e84b236b1f1fcba6cdccddf552498976cef3cd0f7d5f360e33aeff795f3dcdbeb6c5cefcc065f1e88832295bcc4c8bb06de3629a700c2d84e2a00cea23a36004600f5baee70c8095d2f7725b886aaa2c5e5d1f119956304ebcae175dadbfb5ebcce8cea13aa4e5a574e2cd9a7c127d76d84d7ad07bfde2f89f187197f18f7d9e87bf1017fc594b2269b6f57ead3675ff8231f9204af0f923c28821a360e22144c384812811b7531181bf682fbda8b870908d924681d3ee4855501859c92c14a799face3216c22bcafc896739f78dfb880d5813d7b5ff4ae66982a9cf26e2baef79f3b4ed877ee6cb3658ce890eea68fb736841ea8010d433a9c64d2a07948850a96d633953be0e4a116908505dceeb6a70848d8005f1a63bdf1da743ceafa735c9bc7bdce870dce8beafa23d13fe6fb0e608f0d20688113e1f06dc87cb66d40c5e1fd8071f8e8b944383c07121f6844382ef4967d71c2b81e3afc0404d06bcba071e78300127e98be9cb0d7564207e6d6a337375db244a9cd75d6e6916e970f6e3ab0c9ed91bca428ce81bcb1be155046b88a8d042d79cc2d50787f70c4bae0882a094a82029597bb2147b77d7fd992abf53d7f547de21e5071071de6218031c8e6f502428e79a20d2a0ed89a7dea3ed3021216b969b2dbe629dedf69e35962e3791dab63d00ac5ae0bdd9c72e19557c6addf7cb34e785df9d6b3785fff3af0ae2b1bf87a07ae5bef3aeb2df03b9230739ff685171ff0ff366cdac5c38e526ae3b9ab3f2a426024ad17f6c6c3fa222f3f22204438a43b2a7b61915306b9ef0232c1a0f588a3d657bb5c014a092309a4efc7c668405eb7a2e2a06f9f4982124710d7fcf78f8e9bf47a5e7ad2dcfb5f7831363a870877f0f7c3f7f7b6f4949a8bf6d71272b78b6efcace306fc06c291960638de406688683d932d4f9ec339de79a87edbc30484250f827ae02975d39a5deeaa4ae860204e2996fedccb710651ee086f98ea490cd9019c1d6df8884f6290f8ba039f314afa2506410069dc011c1e73a8c0cf1c2aaeb7bd0766c9775b8e5d0d5d3b2f74e29870509743c72f37b8f4b7e7d41dc489112442404799024cb6216df4e9bede5ebccc391201f92e36aecaf5e567ba49e6f43cd8e67d933006c449b304b26dc6206540ca43758c1521162846101b8ce302c8f848128694402ceffbbafddc471efbf2a0f7f47f7f66159d70a28aaddff6db96a8e3181471d0f33a30d7cbfd21d759d0bab5057e264c5efc8e9048085fe996e25fd7e81d34f2aad7978e16de75c49933a322e269386e81240bf2e6a380385a8fa2d224c77708ef385faa124130e479930c26252c63c43868fd0a0985256bbc0f4b54fafd5fbffcae8bbee8a5ffbb53c9e639ee97a3f94ef6fd025ad665c73f76066c364438d24f479f080849d630aa33432419215bc06ab73d444038b2dcc60f7ae0ff19786b59e3c67a086f875e3e6d5c8283df262f10c17186bd077f1ce50ee3fec41b32dfd4dbf0a98ac2e2e0f7e1f31efc3e89e142ce94047ce2e0979c72108717e350b11d02541138302b0fab7881381f5ed82232970f68caa123fddbbff35eef13f189070ae30d2181547b434a4985f090919a601c47e76439cfb91baeda8c0171ea73aac71884ce4dbdb8168cf84c2088609c22fab0154909440608c6ab06ea0e69f8e1c5cdf4f3729c68481e7f771e1fcf02adab30c68bf715eb4cac03de0fbc3f707fb275db5be077121366494808df6f1d271ffde51d9a7119bcf5675285922d82545714195d2adc7439829a6c6c227095dd67b11e39923adb0b791d4a421151bbb6d9dee7480987f6054bd8224343b9c8ade612ca8ab7cb5bbb9258c1f1b346bdd8c8238184a330e8fb0548248ddaef777858afbf9aa3ea8cae09e7149640004995c51236ad6b4948f0be2c8954bbed6e0212167d22247ae0fbe6b652e1ded1859b937a9af21ffcbd213148ddad14e9934b0c36f099fe1ca12af26f181bf70571b211830f84638e38f8fd9c7244e04bc8e1313ebf4aaeb7675e306e6774551a1104aaf92d0fe440af932aeff5b2e83f46e613edb9804d759bb89f555df49cb8b8108697a8d9d1852d3794cfb6216c25edb1ed831903d3bf4cbd4ea2bd45ba61824410481221b7dd20c923ec85eecfd63ed69da7a62a1fc1675527ad03c7c75044f0be5ec2e9f86c19065f6fe0b3036c4272ddfa6d7c0909b364809cb4aa9aae0a73c215c3f22691571ad61b4bb6a4c221098402048354a622b29c0907312e42a2e0f54323dfd32d2c9e2ffa4ce884244f048425134d5887b67feea748445f7b61e58d9b7ab9124892ef1770aea58c4f5d52af9e52279f7ee9891d5619fc8922e6a3d712630442224bebfa92058513ce4282b6a708886d403cc796124e6f1276ff1e2c721b892189eed67fd004705e36faed85aa2899c42074961ca7413ae8f6e2e00f9018e238633c3740a72d74ce71f3e239306b0eafd3ac314548d34623ce883622b2e77a0e68e5cf19c4f7670b483c8fad76aed1fd11c08003c21d57a867ca93fbb9018ec96c48ac92c168e7409518cc1898fb7f549d6958216268089e2c7e879138d0681ec7109d74f88517d47a5a774684ba1d7bac9fe0fb54a7ca67c4f67ef76cf1be31c6cae00b92d08325302ffe00159a648036e5af7d7bee5ca5d6a42eddb889dc59c996859964c201c9830908491a4438a4c421555401eb62b7491adbdbf0fc404282f1cadc5e2c91e8f75fbf70e58b6e2a9de22bb73c3eda7dff64df4fdaf48426a4f5f48ec38e42bc4cda69064a02c292086c213e9b9e90acff3604c49294cdc6ef7ac0564f2b3fdb51db10b9abadbb355803383bd61153e0949418fc2a02efc1ef0889c11612c31c71f007480c719cb1c0276d3e42b20a30bad79a5d77c6fe70b365ed3f71f6b4a08788df09d2060d63066cef7dbc5109ee6c8b88e7d3f3bac7c673d8f3d94fb8de24d689d6fe51afa56436a4de4222a4c0ca648cc149ce0f3cae3802108524c20b49434a1c52127161db099d1a1cefaa6a1e721e720b07c5a98ccc78a4ead44fe8bcdfddcf4078f7436fe0b305839244028b93e812e277c22ce144fb7f7cffdbd39310a0c792ab3022b37712110ab26d947baf9312b12f0d7b10e1f8bbb58801bc5f6c6f9f35024448a4d15d1394b5f5ff78db4d5fef24fb7e496c7a8dbb36afd71199154855e5231c9040c8d6e7b3e9d1391d16fda46d4fd940e236da11b79ed2b1c613bae3580bdbb846de40919b8ccd4215954c55e49718c2069f5189f92406bf8a200c2cf401c3f837b1c4208da30112431c01b43de3669db6cf98461bdaf6cc0bc69df24ada61f5672875f0594774776d499e16069c1d3f23ca4f18007dc9e6226af7348937ce1faecbdcdc338f776d1f396a4cd436d17bdb8c81f4ae8aa926036c4834cf3fa893e8f13e49428af6542ad416bf87c5ef7a5da716d4d81a2da11ca4328a79d9c983c2cb5044844a23c8966133a3e55d678ecf2d97f079f1fbdc4979bf918413bd7ec66763eace6860de93549e32b961b928cc452a2ab6bd05481c3ed5540430acf68e1631404a2444109940d2bcc5b9c78fb8fecda3c6e8fb9d39cee212d7bd599e13f4fd82dcb8f13d6b85eb763808019ca94428c8e6417d481e6cfb206f2ccbfb1edb9f0672771110db0be3b35e1edef594d5ae88af272cfa628e4c11c2a93fb84f0bdef02732450871febd59e4a3dfc3660cb8bf3d19abc575b1e786f17b76003e07f8687c59c0d73e009fe31db7f73d742f5be033d7b1e4e3887951621e0cecb2aac7ffae44ae1e2b02489c051608ab64141aae93dfc7e795b19b1b17a6d2e3a9b1b4f6ff32725deecd09b94654e6cc28b5c91831affeef6ebe476f25e61990f0a92ade263c5fc22b25c8b828090c1bcff5fc8516855a1dff4dc2ef9e641d38def51c4be5e2fdeefef567fad9bef52cf6071b6b3df883d629f5cb6e2a7d71c3ad4a1566cd3e7035b218578a780f361207a9aec8bb0a84c497351707abcf38beb7b588012c81e03d581221c98b547f7a5e1675fb25cd75ef2d7fa56cc4ac2671eb43ac074ee9131646757ce7d0d1a96fd69ba6d43137745977e0bb063f1bd36113a1d43c2c919024229c4868bd57df2b6b4fb9f1da3198767ffa8ad6cb5452375535a79ade507edb83b95fda1ec80b260b7caf9f53a4e54b9c3f9eeb93244c9fbcbab2a04a902aae00e3afcf1b4672a83e7760c1910a91b6fee5cd4e3e567330077d7ef861248910c1a022fd1c0847c6e21fbcd705e940a568bbcb5b87d87f3efad5c53fbcad09e18a7b7e6f7eaee678abdeaedcb2fc031533e6063b2598fe6ccef514bddea7e2a2f5f65ddcf393799d5c24fa76e2cba22ad94bacc1adaf518924611a1fe5f00a47fb3e6f3261bc6609354012cb4fa2e2ca162a34a9d293fb4d792595d21fb6beb70ac659e6a885f3057bf38980be4a59a7830ed63180b4d36cf4817faf6f1140db00270c88f7f505306ac252f95e45ad684a9d00dbde36545ca68f73e2802bda95b6844a9b09c3235e9822e34072c4b8abadbaa2b6bb084838713f7a207da886377c21da8db8ff385295136189c11b0712e40d15e055e213eddb8370f046164671bfedc17bf0cb0f7821fab369c30b1597cf5819a0daa0f7087007f6cd8b50e558abadabdd08d43322d70cb81eb98178c1502435380e1fe7418485088ee0b477dc3f5cb4b0f739d4ac0ee2ba8852af8cbfe5b309a72b35acd5802da7a52b555cb065ca2837f99d3f80903690f9de8231f0a9b8687d9c1c6373f9201bb363ef132ffa3be3d49f6e4df3c008f22ccc62f519212208def725e33b656a0874d715ef2f55be315b5fb667bce8177fb965161390002f3f8ed416ba7e261ce48e4bce1ad9de799307ee3fa505c6a9e0f77842527970f92b7fb409667c7cde867e679c68bf76ee3e87d6ef66f0fadcd3699f13e328dd780318c5e4b690dd44406464230f24a2ffdfc87aa5eeb32ad83d514a0cc9bca102bc4a7cc6f739220e84f8032931f88c974924862c1cfcd59418a4118c251f8a0311fef9810788e0401ad46e36a8b3dec0675e705d8be3906d348544d77102e2772634b4a04842913601fa7ed575e30d0346bc787c7d3be07efdfba4efbfba7afd7aa51e5970d1c33dd728b574c86f115bbf715566d5668fce988c8d823108f46a1a1d934158071f348e8066253242663a6fb9b98a826c67091897c4eb205904b9f4eaf2d90e03bcaefc715684afb767bcd86f1567971d45190ef840146edf4c508860c80054922cc2b81f045b1ea8ffb81601b40de0f7264984243a4d982bc655348de6b08b313ef4fd480209c7f7f91c1212657ab79abd6a2379a2641019d23e972a59a9c2adb62d64777b618983c2ed5bcdd5a6ba261bac38a805a58df9cd4b8e2e0c9cde835fc98d27269cd2c0c754455e7c81c64b9fc4609e4369c467e3e0f7abd01273ca4111ef2c81046c787980080e84f01dee648fb9ef78a50efd39fbdffb23a92245a2728e9c53bd90080d1bdb607cf3796b501a732b09140b91346489dc5f3d7f171c4f3cc7f66ac3db9efef8267dfe37fae0b6cb5a2a55fa7bf1dc052d30032a8e3188cd4b62c6e014e764c61fe0c6cc0740b2c4dbb69ea3d343f3a2f3f3b5da58d78d700f3266fb559d89d781dc0ff2a08f88f7150c852f854e75256ac7eb7d18aa9d3a9e722c51524c9f719822c3a91f14318ef92552c52da2fe99cd4efcb3741a70e72734d46aeb468e3b01818581aa582151a65d57f3813af096234d4248a8ac7dfb4e3a85a8807e60db535e5871ba6667b8dac74d02262506dfc2ce177efd82a34ba02ab20dbe00551179e9c45445369e6b0e7a7fc47bc4834f72b273e0d545f882536d78c61de856198b440f9a9731021f1d5076fcb8adffa64cabf38c52279f7269b8572f97605b1f51ae9cf4c70c247f714e79400405120a1312d2a1caf80882c2586f89bfb32d46afb30e734e5ce91af7ee993be8fd136074256f11a94a936e9155713af6315d060f5eb850a917ac1b9ec81da8d42ab5b4d110378dbd6d948a8e7f9ee9bb19acdfc5bcb0d81be87beff3989090917f1b6ddf469923a34919f5735252e3d69b4cee392489aad36feb0be33a2f23e424b399057af379f0fb23dea96ff0a594a40ea0d418b8d39ff283084a6ff13bedd86cef752ce94504fca7371b30021836c09daf50b7d4171acc543146437c3f474a94010c66ca8b2947a4a19e8db471b0338d545d4986ef6f63030968d101df84823481c911e9a00fe0907654554412c30eaa8a7c9c1db903e7b304b243124360f6e1ed35b60ae372edd7ea571d7f9d52ff6bffea03cf68cef8a0470fcf6b028e9ab27846dda9555c364f4a8120090ad94e3e053c59c0bede3ebb11ea0335f79e470f6ab6af5217be7f47cfe177ea710da957f707bdeeeeebf161bd9b517889236689701141c102c74cb091d635de6e7c6bf51ab7a0d50bf7fff7b867f7516ae9a6f96fbef6a38a9b67b13e22fcbd79c55410611211f17c1052c11d3c5fb6e8c62b51996e12459f842ab3eda2c053e0fa0d625c826c39d54da1932cfbabe46cb1ce422f871e6302922de6c5d9f6ef3edb19416a1101ffa18d096902c923da22ee9e09fdbbd1ccb8ef279c26b61150eb6530573a875be64ebf8a55120a12f9717df5250ed9f63001719b73a953e9be685255114b20011cddf6aa8af285c4b09daa221f6737872b12423591444510b4c18372256dafb135c0ebacf63df51ffdb7beb27b9f3b8b3ffe48a9cbb21f6c71b616756b1e53a77e2d14a2e1b4d0e06098a0484905f50758159600b66f77dcc9356b2875eff20f5ebefa3da55aed97654daead176dba75f9a9711c7acd2db5ef7b7ab1be6ef0fb331faa54aae18cfdbea959d38b8f0809736c58091cb8462922ca947a7551af05795d959a3b64d2b8c7f473aa52aace8f56aa93eb23ce599403dc44723c964c3ef63e97ad7163e2c63551dd10edc7387a8c56304843b0fe8224deed8d200f60841c29010bdb6102db9097b3c5f7495f5cb369a35f94b74504b4bd50da92feb1368eeab648403f6c803bd3d67ba1371ab905d9e8fbd9de73414a24b1ef89fe183e1fdfe1e74855f1d8c4cfafb6c4110efac39e222011c0b07ecd9e8ea974964c55149c1bcaf4b7575574a19018765255a425101bf88424c5e3b13de35662dc3eaf336527999788c0e7796ea0d719f085ee4c9dbeef254a65947578b6df14a56e5df1dacfa38e55eafa179ebdedba6b953af3b46b1ecdbac9f58cb2eea6e46c3ec2d2d1c03452856989e5daf14fe71e32541382e68316dcb5454b1a23efdc34e33ffade4b6a5ef6eac5faa20daa5f8b0509086077f5b0f58952b57eabbbf80e7ddfcddfbefcea174728755adb2b27646418fc6ca379247e06e38cb838f029f2d9cdbd34a8a1fdf897472bf5c519fdcfeea1f194d85b87ccbd286e5e4e5227d0d1cab98a449c027b191101210e1bf771b3f56f673a515f3287e27afc9c22492059f1fd9d8e20af3e23d43b1e9fe3b70d79c78bfd5763609d06075ea554dd760d66d7385d256e610145dbfee47cff9f34db0097910e2d0aed9f9119f7fd64260c29a106e5505bed4ce5cc0ab6f739b46f7c0405cd2791c8160e7a913de4c6ebb1faf757d1c2ab811c17896c1439bebd5959835445f94262d85955d11caec54ec64cafc4106cfc4a7c80ec2eafb3800324f476ea0cf78068b2aae5570f684ebce331a7b51e3d5a13821b3e5835f559a5ee5e36e8fccf6ed5b0c17b470dba5aa97bf61f74e23b9ab0dcf7ebe0d3bfd39cff83ed3f2e9bff9a52cd4765f69bac39ffb4f76bcdecfba3722bdc8d3a68d0361803e27845e478ea88b4ab8ee9a4d489adce3bf5eb12a5aee9f2e481ddce3133215332d00620632d491214c0e6d69b987cf857372f6aa5d433b3af29baee0fa556b658f2e77b99ee1f9de3495545d961298b2ca71327027201be84e3851ecef27de7e1e8fa664982be8b773d680964db043fc03dd3a7ea7498714119017a5eb519212f3ec9d9a26fdd6fddefaa140fc9fbf78083969a2b2cbcb7cf3946e8d4abad1a49f6f7bdbcf95284c44906976ebc7fc97eafebff3e2b54b3bd5b2297be5f6c1fd3f7ab9e44a9544c0209b0552675970e57efbd626d4fc581c435bde04d8a3a108ad8c16cfabe485b8ea0c5f5d9c2c8e888eb6291ca38b8189f377790c3d7399e71385e4ec09191cf8c4f65019f39a81d7140cae7c4c647e3cef6cc837c8fd8f8685eb23df320df37763f5dd75ecc73e2f71011efd68a508d7df7d587f680b48b5c63775a56fa88b326ebfe55e9ff3bff7c7d88df90727027d7bdf302ebf3e697c573de81efebf97e32125b7e37f580fa639fe7953af084762fbd3c4bbff67f3fbb6a66032de99cf6e484eea8494eb61ab2b900334b1454b8c84d5a57d466d34d1b8729f562ee0d573fdb4da987ac6ef54f82cda308b5cd8ba8521edc56b9a4aa2028e46de4310e77b5bae27d6ceffb7823c8b504e29d7fff3acc16df29db834f46906751b2d1c075b06dfc0e7bf978f0cbef71f0811dcf391139add8cd1be706a707c7c1c801aa32608d088c99a15da07bdfbb9acf6d3da254eb9e1defbeb6b5fb9b13553925fb7ef29c60233b9d5b4d9cf4406f2a40291132c15789ff9ebcfd05361035ce69eb524827a6ca21ce9f16b2a1bc417eee7eddad97f30aca0d4491e3dd252716a022607c01920479c17417712001a266a031940eced94974e422302d59c47b9c7bb113302f633ce30ed4b5621cb37d1c347d37db332f7ea78488c067ee1be2fdbe41f36ccdb71ad4d647f4019ddbad7afc27a5eeba3d6fcad36729d5eaccac99f5a71bcc64c4a7c871527171ae262af0739fc6fbb17330153ae21adca40213751c2a6103e08038e20169e5b97d1021bf6a3540e519a0e2daee08f25841a96daedf40c95a79f153c4bb23545c8d6f6a7e44e76f95aaf57dbde135a0caf4c5179ce2ed4b2f3c3ea8a4ce3dacfe99cd060c7b61bc113bb54eda9453b5c4ee24dbc722c9a54fc5458ceb3dce8d5638603cf2f7a0ebb6bbfd1546f42aa18292221b2d6c7fa9583351a4e2aaee4654c2ab2be64ee93d30a58a20b9178ce1f08778e340020f4cbff192c66dde83031203545cbce1c5c11fe4069ae535ee27cb6aec4b99210b606579239f39995fb08d27e14267154d775f4a19c918780f4210c0baf51b2c3bbbae52570ee85336b4835267bf7263e611879b1b3820d2dcc111d09c0d952ae751b658cae1244aa99271be7230f0887a296c047567e05bab962b89c40efa00e3f81ca45a0950716d7704b92d9c2e02d6af13e4841140f0e5ba0ae5a60edfe75cfdca0b2e69dd190499250d221c7dbd9024134eda8769f37903fd536d24612f8c271c3ddbbf38a25d3bfddf2d42758ee8a5e2bcacbc1a0635461acb03545c247fbf1b53614942e2cb00b1cbe6fdaf9040945ae9fe938093357de985b59da562b72131187c31774a1bcfdde6c11f687b20afaeeee2e097de50e2e08f335e7a0fc8d9d0698b0513ac230fe0745962f0e65e4a5691cee7c61cf112eeb848ea88171fcf4bf5188318beacf87ed21af28231487d2fed8f03ae54ea983bba341d74b05257f47b78fca9a79a275160241d681caf40c6774a6a4715f5446956999a8303e412a4e4b086a82b3ce30c8bef4fdf4f38353852b21611c881363f9a87dec2e92228075790e41e90be3d88a1387068d6e0b310e94c39957c258101397e8824122228749062a47cd0daea1fd582926fba04a4f165fbdf75bf6b7b8b387dddf9915e57beefe767a4bceb8af6f1db9a8450135e58bbaffd151288e3ec1bfd8fd886b0a3bffb7243f90e603a686c73dd76aa8ac86ba5faaaa230f0790f7e123163f86ce00b039ff7e00f2e8065c78f5b73f8e80b955cb650150573ba112f3e6feea504f31211f80421f78e3b4112cade09e7253901b4812fd93cd3c6f1be87e4d08f57f7a78e57aa75f38ecdfa7552eaeaa18f7ffe1fa8b652e96003a74c1b99664012145f52c08f701dae270984655b9ac9eabc77b292bb3102ea9dd720e3b82df0f9253d2ffe18e392f83bd9dca77de961286a75a8bb7f3bcdfa753af8ac3fff8579a1b81de9ce4dbf73a0a89438e860b3f1fb6e3fe8f6500b03da0610a174dffb16eb95473aacd673f25dca63e7bf14cf0026f97e52a20c92fcef756aec799560caee41eb8b802491577322471c78ca2ab7187ce8e894eb8f3a2a3ac9615c6c9659d8f4ad81aa28da6f6a38737d5d66b45f88ebc3e67a8bfa19c644a7afcb00be3ce0cb31f880bf03e1b3fa015f06f0e5015f0ef045802f07f86ce0eb017c3d81af27f045802f07f86ce0eb61f0619cb6790ffd7e346ef31e882b519dcc7bc7e605ef4df39287f7c8e17930cf198bf7c8c07bcc51b9069f35c58b8fdf2303f8f2808fc61d013e9a071bf82e02be3c312f11e0cb013e1bf87a78c63d16ef8179d0f83281cfc6bcf4f0cc4b18f394877e8e581f63715f06de639c15496dae5403d5f4a253b424724c9b335a1e788052cbd6cf9f3371a2521b37acd958f646f40e9f5755d581808b0089b0a0067cd59706aa3c40f3c6d1755ef7a0861fb86ecd6d271cb3efbdf746dfdb4af8de5966bde8af81f520d657a1585fb1f7eb81ebcc3c58c06f03df409a67e0abeefa95dfc906fe42c69f07fc9e75d1ecb1569fb53d4da95f52239f7d3d4fcfd18f15fdcb903287eb7e1041fe7fec7d77605455d6f87d93425540042c28a189065054c4b5918958f613bb045d154d5c5c0bbbbaea5ad6c68bbaeaeaea2a2aabd8829505549a28b6bc8080080a0a845e8288945002a46732bffbe69e73dedcf3e6e64d4050bfdf77ffc8cd9d7973deb9f5f4735175a864348f005fab8f23d561a8d78adf66295055e80da84b54ed3230e76ecb7be1993e723c3787b6f61c183b2fd4d316db777cfe2cd8c7b80f6d687786f9136afdeff8dbe62317970bf1ed639f7df15d1bf505bf0992bc14ab544d715018ff84296bc059c4372f0eeff02f2181dc141d19fba790a98ab298aac8f37377d4733e4e595715906ac7a02a1a047ef84c5514ec4e6950150d82f6deaa8ad0c633489718a261c66927ebc6cc6d48c973a20c9ec186e48d3383a7ab128d1203aa4e32992a918bf2ceded9905a766c7dc405170a71ed930f6f1adf4b880b3bdd7ce771db558f30309238659eaa4561e41547242e71cf45fd2a23bddf5e6a9ec4ebcb6783e2b60c068f3851834a2350d5c9e6c946fc0d363380df24bfd9135dd70b7151cead17e7a8882ee31ddc741737aab2186349e31c861adbbfb5e2a88abbcdbafdbea3dfab3767c9110e3d9bb2f4d26745431a06d5e6b642de3648fee2b53815d67e2bbf800472dca6018b410299091248624e761e719c4a62f0382613a7acda7e8e2b36ad526250ed9ed036490c45206023a7ec001e16937c4683c4d0d30278d02e619c32b63d7836c0d3fb313a5062c806780ec053bfb7e9f738ead88f61008f8f8ba3c1f3c6355fc3bb484fb5469c743f92f4f2138e4bb0c4a0de5b0cdff72389908fb30df0b2019e8e77913e0e12de48803710e0c5be0fb508ddd9ea62210efba86b8f4b24679679e5296595770931f7fb8f972f9ca43a0882882791a08aeb55f87cb3fe3d969804d2abcdad693f4a0964665f9040988457049c66969a5f39bbbd00efb0d66f2e591741db2459dbe2bc587334c033ac37b93e70bd227c05af00d65b364980198047676887e1779da1bb1abe2d67b769d3ab54888af3777570e4139be7942cdbfe817a30b24ad5751da106db52fd35aa26d604254138fa7e73467547553c49618a9440869ef9cf9423d708d1b6eed0cfa62e96df75b386b839ea1248946a7c69fe98a4ee804408eb5fce961aa5ceba4459f68fcde58be57bbeddf4d982ffdd12c80b9003354862c01bff7cc9e07e5e89419892cb9923de7589617192eec63c4d370ff4da575e677b2b3170afb3e00b9e1a9618b80d29c8f81c0ef03a1334bf0da794b95754baf1236d9f397c4b6eaefa653acb05c6d3de87e03e15ce10696e9ac78add6e1d0dca863b8e05c61a8cd846af35be4f4c81b64101abdeb86af0d10695acdb79b463746c441e34cd3f3e60fe01dfa807f815aa3cb719dd3783840258145f565847fcba8ba32adf55c8727d9c71fba00b9b49d27ec888ce156336ca0fcf1135ed068b04de71060d03cfa1166612a59df87cabdf54ff61a4ee67ef6940f925bcb0268b0bdda51a3547c6dab1b6ef46427e00b383df6c5c56ef4137ca9f4b554491e83f93aa88671ff63676e2033359af336f01da6c5c1c1d5e925e6741aa4454a1e181e71da81c5e725e6704cfa0eaf16ee84b8e31c88eb64542d0e45c5563d2404cd942aa18c8fde54b6b1f7fe09d2e5e8ad5a6f9f218988619224f6554a8f79bef139a271d9e699ff855b4dafa8a32c2170dc8c1157daefe30d7fdf99b73a7f57f44128c39cba6ac5bf50a8c539ca641ab71fcd0cd9aabb2b0c6e71847ff8babb6c2503baaf2a54587feb884f28c8acbce7fb6b5fcecbfd6cebe7db5759c2c83c5d78703ed2cf85661c1ceb7daef6ab250c2082a688bdafbb2af088863fe2ada29dacffdde7777b32f3216efb8c68399080c5fd8c8c13178f01c6e8ca840375e741fd5e179ef55cf7bf8c1ef710275f81e3cc22f0ccf6569cf65b17e107ecc26e0f5177fc7decb36b8cdee4a47424691ca8c73e411c71e7e0a6f9bf00b03bc2c8007e34cf8f171d1da1e7ef49e2cedf7997ab2cc04f3c6c68f71d4a6c8ec2c46c8bd718e3d5fff7c7d6bdcf8787f42f339aa6efab8aa314b715a1f55935b300b94730fbc68b598c4f0e7f3a5f0cc6177e767b1798efad661d4303e0a3e839760ddf0f1373da7e065b175c0c6bffcf4b2a7961f2ac4eb4fdebbf2baae42ccbafc8377173eafc681526730c21062f12029a648769450f8ef385c4e581ca86df1f394b00e8f13b810c75ff6eb8cf0a0b79a4b89e3efe2ed889b2a2774704a6bf79a01fff9a38fafff1c309e177adb3f9f317835732ab7b8297c12159221b138f0f95e1392fd4440349de726a134cadc48c7384d311639e8004e36c9c03684279fc3802e5b3da54b2222d9c036c8ae6a74a7f4738e85002f6c80a71bf793cf6564c7e38dfda0649426151771f48ca331b98112bc00d586cf4fdd2051993868c1545026bf777f64b69d181e53d5f58f7e8e0702651d86fb527ce9ecaf50351d704ce5122320a1fa2bdd83cdb88e094f76a1145f0f5cf5668a8f42c921f8022dd5662acf2857ed390c5fb67e2b9bedea59922bc4fbdf3d5dfa640b2176ff6dfb6d9590fa852ee462358e041622089c60e0418c07f30cfd797e256b8813143e1fecc027c212509bd29d936451c46a89d71f86dd3bbe5d7b29801e7269e64715f2b35353875df19248a4a2c47da69f0f81b9cf683e615e988681a940eb1ea919822978b050f24f07da9c6084d9f38d2628298dfd4172c53701e8d6261742a761bd0fdae2a613ff7d8b2fb333e43363acbbdadc16fb3a1cfb0d1a150792fbae72e7252323b8777aeebbea7932fa817109dcdbc85d6e20180d6d6bbc7a0e36201a154b7437586193fbaf03f0b2019e0df00603bc20774a1be0e5c1736180d719fa1706789d35f816738365c6359f71941b5b4b2c2070308ea399511cdf93ac1b730918a96dd113e015b07171005e36c0b3015e5e3cde16b963f371a179cbd3c6a5841b190d4e0925caa82ce1f5d2c6058e058417e91a79a542cedc8c35ef954dc25425afe975e40855d7bd0335b8a7d6032b4189b373a514734deb12d766d27d52dfbbeebe1b301571eb18ddad6dd66f72d7c5f953c65263bf8b58bffd4e0d6a9cb9bb2eed13b6de4ceee1b96a1e6be657fcfda7a38498b4f5f9618fbe2bc4b697366c2f5b00e3016eba649cc51a23fc0ff7be1f5635f2fec90709d1fbd3334eaeea20c4f799cee38b5d9bc0eafad7d13c4fa94f500586e705aabcf2588d073dfc1e56b02f69a0ec3b0c4992751ec30309c6000faf5bda8ebc3f5bc26d37e5c8e87bf3e4678bad938f9b20bcf92b817d9141fb42b54b02dce44df35744e1081909e18313cd0f672ceb375de2bd7cd1bc37d78e56f852668515aaae394cd564446781b3e8c64e2cb3037598b5a9ec2f0282290de4902c1f33a7748be4642a0acad2c66d11a2c3f0ce151def93dcde92b4944cf728a6380188d3002f1ddf81c90e86b88da90696792b91d74f31c17b12e0213fe3c05f3c301d06cf0678f900cf0678f900cf61f06c80a7be37c7afa836d804242169afe01141e4077f118367033cede017e02f6ee52bafaeb803d8d6c6050f7eee15e6793fd9006f18c0e3e3e2307836c0cbd7decbe357301e269fe62d3fe1b878de68450c9e0df0149eb83ef28931e0e31c7b3ed2ad6e4d453b21befce2bd6d9320db2ee6baaa03af2bcaa1f523b47f82e73022fd7555bb5bba456aab9b52df12a25bffbeb35d0212371e19301e05b1b689c099bcd738431486f9c47ef7032f2c07bcb0282e08c6b5c8b04f02e269eaeeabb24b25eb31f5ea510f3f365b884dcfae99b5f529180ff0aa425d3b72bc985b8cee673955882127e7d75ee31ad9971cb87ad09d52dabbbad9a503cf17a26fd6ef6b4fbf4a88c3da769b307fbe104be7cca9d8f19dfa5dca0faa2655d13aa851758804c78aef591ca180ef434868b2d9f3863ad405ea7cf6de87253dbde2e137bac8f79f939277d78bff91fd58d23ced1f43e56f1f11e7b51921fcf3970b84c45b9f0a1b1bf629329ab49f818c9ae62f0cf08a0c8c6c9e82b764e857d33f3c4988752f16cfdc04d71010e1c0543d10af43046425d490890119a868277813be11cb5ad6dee704046b9cf8380abfad6e4365e4152116bd5bb4e63349013ba6f578f50749e99ba51ed8379673e74831dc5531c8815207a0ffc0cc88b533920c6cebc72486fc464a0c3cb0ad1fb93be600bc0a782e0cf0d4f7268941308961a092182cb33bb00df032005e01c03311c091d0ee09e352c0c6458d53b6cf8d392f1e6f2e311839253a000338e7464a0c46b7584e004b48c244c62003e015c48f4bfd1b75a754b477737abe3f61ca1dea094e382867166cb8da09aaa61b0b7183c937b658d2bacc35ba776f79e2532081581a5e660267436f159ede3a56ed12365fbcdfc9ba41fb25eb0c353e89d7c3b496aff61d7eade468c72e1dba2913fa8fe3006ea17820d52c871a08894b582e3ff09ef517b712a2ed791d6f18fe9a50eb23cf5b07d68ad031ee3502ad1e6e3ffe1a591f7fe759d38f900758c6885ec76d7f46f26375b3a66c512b43a4c0418ea95342d7a9da4730f0c007c98552a7e4b1ef99ea8c54644840fe28c4b5473f34abfb39429c75d1906bfeb64b8803d71c5cf3ea03ee6f42a5bdfe22d439d459c4cf5f2e8c2f8e37b499c4172c49279e3f848f8484ef336034e6fccf944e2e43be75e38617cbe0de1e4e38709eaa0e5135057c82c44d044433028806023bf7310181ae7b0404269e7499c069b89cc7f20d739f59293770fdfbf56d3e937587c99deec85a289fc90c2d6bd55d98233739a7ec570da889f44b0cb1b6912308f2cb2f8603b098543b7ba72af222c79f04781900af00e0f103533ff8b9aaa858b400780e608307910dcfe5417f55bf8222de6d5225c201c83825bfc460c3731900af00e0357ca0369631f038bca41883c89975b67b53e197cefb4fb9174fb985240eccc68b2a99eed0060212014283a2bedbd316a9addbbb2aac6ec3fafe8b492080178c27321886086f5fbc8ba742b5e16d305f3a4344fb229badafa224256b580f5b42eb4639c38598fdf5843ed3e15c40d51d1d4090bdb81a0ea6ea6aa85f12e2e26db7560de82ac4a11f743be65177dc72459ebbbf7d2a185c076bc4d5ae9b6f4a76da9bc7dd2a0feadd6dbb5c2d259c7ef5e7bd78d1d342f46edbffde1692f5397848c721650749823664e95bbb17c9b1ffb0ae06770411162410261bcbc350cff0ea36fd0fc948bb5e883ffdf95f136ee821c419a70c3ae4e9de421cd0e5a0198f7493bf3d2fe5a053e4816bd55b9fc5bcf24c8c1b8e37ce5fae3ae502254aae6237cd5f18e099f659811573079abaf5e5766fca7ed66dab995af312cc17645e20427fa5375f6e410984c781f80888b1a4063db067058d374847c8bc081349815a80701db84fd63d2ec4c29e855bd63e22ff4fab5e7de345429c78cbfffcfb3f374b54c369b7755a2b1fcab262a61ecb89c606381ab662d0adc2289025f4c6828d8346e46cd08c0e57ee9e388d51f0c64211118d8c56218a8cf07b7c8f0defcd061b03a4d5465d24fdbec842235736c0031315e15dc8e0d9d00f484a6e156abf2f62ed420b47355feb07e201fdf5c685f0c987fe67c17b553fc17887042a6e1cf03d2a30d1f18d8b03fd0803bce1000f091ec7bb90c11b1e302e850c9ede8f4281cbdd06787c9c71ded4383d21d4f1375c900a2474178c5039d4f0b9053733c256f574ecc089c7cc9c078a7b636f769465242ac4990a4fc40bc6d386f9403c102f87b57deb187e57c4da8bf93804f43b1bbdef00ab7cd5ded175cb3fe75f28c407539f3ea26084faae0e541cb5a8aa02425b0381974848dcefcfeb79c359a7dc26c46129475dfff86cd7901e1d1efa87d7ff288e9d791d68f88624577bd44f42b41407d9ae4dbee767a7e5bb75e6a053d7efde2d71eb5b7b6ca1fca0aeaca6f9e276f20c59587fc94e8997b5c8aaaa7d57d6432dabee3e09efa1e8837592e4a6ffa5c9991d24614ff973da693d6e90f5a6d49d3d24c108cd0a1dd0fd18e1badb96346b26dc837e934be2093fc457e86ddff8f2f9f3cf271272fd3cf0ef6713fc22369fb82f62edc89c9a6bddfe57aedcfde75a60d0a3e0e480eb36fa37d6fe2bb43f869a393d245ff691048245526955f008038ae25369a1ce136d2572884aeb7f78a75c1e31eb2a8abb7c2c3986c31fed71e3c152226932b6594a8fdf8b384e99eb10939318485564d6ad6700bc028097586228a648f4bd53153189218ef3b6015e1ef4370cf0748981ab8a8a81e3251b922107974962e0c6ba71ba7343032a98c4124309937cc6412eb1814c62301a17717e133b51c4d990745522cbc155ff565d9e2b81cc5cfdc15353c00d1575fb5c678c9c760dd84250e4c7c86997536b3eb9759dcba1766b75e2a7779f1c9b1fd54fcf76941bc38324109454b9c417b08eb96acfcb999603bfb31aeab7cf763643a4d5cbfe7c3cfa95822786c5bcabf2cae1a0a9bd978d470d1b0ff9f980b4210f1cbb5588ae6f1cffd4888972efe6583bd2ddf4f716c79faf5f2e39027e41e371b035d55569a74453eb7b9c2b44da9f9a5c79bae49c9bbcdaecd9014325a158d874f039f2fbf4922639bf97e743bad5ec23377b70cacd6977f5970764cae294ea580e2a61e576f89dac57593531afbbeca0fdd6487c730d1225d700706711d3fc99ce1fc0b7eaa7f287d7cbf539ab7462d927304f2441a3e481f386f3f8a2aa2977d910556304bacf886e2cfb8a80ac5515a9b26c6823e118ad7f4f4a9a7cfdfb90e4f1ab36956f7693b22d1935f3f5996f4bd1f395439b96c8e70eac3e78ecc99273b4aaad9bd36f10f1c6db8c58cd554559b0a047e241a35445356d2b4ffee91d49b0eef961b8237fb9fa9905674e96846ae9a1b3cf99f88c105f1ff261fa98a385587ef5dcb61f4a4e6c7d9f65d33e7b45e2e594b7582c0f12eb71eb8f3b66bab103cd0f73addfd62da1264d8f168d5715f5635e6726a35ab2aaa27e70702569434ad6eb2c89247036c053fd26db4623bdcef801d2581b9281318814d6f58f1190fc0f9e9e324541226f95aba08ebb80ca2d3590dd170908dd0f2209488b6b5b2d88119009273eea1210d9ffb580871a8f121adfdcd8e7dca9c15b27b96c3c54bfbc75acdac1c93213f65b62a39e07d56ded9b95176dfe5a8ec32def5d3fb9addebf6a50752001a9fe03b45f16e2b49b2edddcbd9b10c71c715ac10b27b97687d0e466634522860bda7870e2fae5b601a3513fe178908a9933145c65c4192b4184541b0f09cf82b60e2f797c8be039d5c6649444b8a11dc40099e6af08090bacf702d82780eff6d19bbe58f06f21be7974da9a3990fc13558eb47e519204d51519d1210094bc1021a928b9f3ae1501c50a7a60ef0a2720ae4ef2d049dd9e7275c63f5db8f20efc1ed36ea742923bf4c76f0a2a84a6bf57350678b911c35d671ebff348d9f17e951754e43bf2bbb79a171cebe6e2416fa87ca6032e56edead6950f9648d2f16dc7699151db25617a7556edea6bd59338704889c9eb060f0cf073a7f4de70c5aa582c712c6a999b76b810fd870fbe2cdb8e39059c71c92512d7754d4b0e7727cabcb01596c51243b778d97dd5f79c2385b134e68612646445783d019e03dfea07bf6de294e8a056ef1d076f1eccbcce689c698326c6db070fae041e6c2d318c0b872734bcb98e7f1ce4fef2e08944e3529b555dbe658b104f9c73cd7537dca0bea850245b94dfa9d73b77aada559db80575fe683371ef0769f7c591954d9a0871eeeaebe76dbbc51d4fc4970869be1a2772ab1e0c6d07f054e36d1be6c764cbc8268239527b9f693db0f9af1f5a5f512d39f182b4bfbf7b8364782227d42eae8683a51c547ad5703570e5c7429cb0f89c8f0f9784e5a453cfbbe5c543e45ebe32a557ab0566f871f8e743db56fd84b6373ed9da78240f8faf2b9b8d8f93e478e07a56f0f269dd2687af7ffef2017ed03e407c75f81c5ff44e34ec8b65cbe7defc9a3c07c76e7e62cb44309ed37a0695eceebe7a7b273c873772220345f7e08057229edb2491f8cabe0a243415478e53f59005af5d23c49513f2ffe348c4ce7deffa9bdca4636e419b08a681c68ee1c6ad3c19ea7e42ac3a6dfe81ab25c57cf7ac870ef9e30f427cfec6e897cf6f2107e5a25d59731e1714a9593ba0eae61fa588376dcaab6fe47e28c4dbd38657dd3243118e458a57f50df46e10e5778197ce4ed0fd9695410d46d532d025ee3847be376b774169a9109f38af5df05e6f215efbf4eed6d7ac16e2a32f5e5efa876512e7c9bbc4f76e364e87451a0fa7486f88a43646d44380178b78775804ab17990d014b0111f53c72d910f14e11f78608e74644bc033c91a3c17344e27ef823bcb57ec4e1a7f7c3d123ea699ccf326f07536930c0ea52a84d11de384e98dbcdf6451c67b1dfb179308cc720ca80108def676044337c1eba2a34a78964d0aedcf9e07b0fc9a32863fdb119ed8ba1bf92816af141eb9753ff21c415afdf7ffc1db74bc23162e08bef6e9407d721d63897703436a23ec1ddfce184e3c13354f0f1308f0fc2cf6ad4789823f693c397cf5fe0bef2e1dbe0fc61060513fedfcf99de767eabd8933e8697ae62fe82d5c800e34e08439bd94278db5ff6b50d04240c324a4ae1ab775df83237adb1b52254f1fb3942342f6eb5e41ad9d1eeaf9c74847bd02f7965e69aa510928f5e1314405402801d55e100442501da192ddd5e2e37c0e267bf3ce5d34f2567b8f188b93f49ce70e6f071bd5e949cd5c6c7563fbf0d44710c84aafb93aab97b62f52950a397097a9f804848ba6008acaa7d06da40506ad17be57e49649ede3c7ed77342140f9879c8a7a70971d4fc7ef77791fd485fdde4c14e19223ea02e7176559f3714798f65c0a814c4fe722f1b54998c06afaec6deffc16d0f39ca46634d35a8b84a1a0e7cf4b929e6800e7f2aa89cb88a2bc08dd9a74acb010e8fe0311517a892226fd43d5d2e198559df4da89ad24e3dc9afb2a5f8865ba18d596613a9b09ab6badf5561753de784ee3115164a66e4dd47b622e51cd1ce375f05d04f9df3cc609c32f7ba9b0af04c2a2eb32d4a839f7a69fa55ade4baedf2d5710f9df3b614588f3ee37727ee12a24ffd590f5fdf4d4ad607b43cb6f7fb225ea7aff035ab3c1d6861bb00dab91afe45c6f5dbf07894c029e0ad2b1bc627a3a1f1f0e1ebc1c7534587b7a7f88e067826155792f87a92148e23ec0b5071452aeb6eda7da21013fb3cfff8dbaed7dbf3d1f76bd1eb0acf27e63587b6adea43551d81f88f48dc7a8ed59cc57284a1ec2b09c4863aacb75d82122d89c63616716896283fe069219a8d689935ea65212edff6c0752f7610e2d017ba0d6a0692890570b063f578510d1ed4a05270377ef48afa47aaa4c8fde9f3af4d9eb043882dd53f0cdaa2941ba26234d428e24d85badc507f08f549ac0df5eed7f59abeff9b1f5eed84ead777c909ffe0f6a77b3ff0a094489e297fed9b961e2722fcd9559d589b272fb4d5f30992eec5da71f06c8017067885002f0cf0d4ef1d8207fc46d48e7f2fa53a19674cfa662b780cefa0acc6e328058c03ef054e0e9ef75f99abe18dfda07118c752ca18c6257247dd0d55a09a3116c0c8554d265172155ea6943ad0366547c6f9f22545649223bf67e6988653c644fda931d838eaf88a2a7152ca979260fcd4a2b97bf3a0d526747af327e3e08775f8c29ce43321fe22e8c6cb64c70339faa0ecd6415761f36cd9fe248689f135ed37c7908cd4846fc0cda5512f755196363e006fc7d39b6efbee12d93ebafeaa7ac6d804d5285113033e5c6f071bcfb1ec2b09c456154a2014e1290956af57b35a5f32517e3729f47aef03848f330a7d9472bc1b917e44e7ccf1bde5371b6a965f39ed13b9be57edfe368a0405e0214f8057a9d45f0b35da2ac0bb00757a753da086c8d75a3016d600e789c6c26ac8c24a9208506cf2af46ef068c13000eb60e03ae90b2c34d6c75433c7c6a2755ad7139dd8d7d563d34fd612979f5ef37e4fcb9b24fbfb31e6bde3381c4c0bca11a8878571c2f1ae76c901838c7c5bca17c5e25dcf6e0c1ab80e7f43810b3f112df9301f0543f1a29319838679ff13d07e240a612e7efc05fe41463cf573f5ef9c5c6638498b3794acde72c25874f125d0f6d304252e015d4ae91514a20bd5c09a4cbd9277ca8241070b3e511e4a375af38cb176f14e02cc125b279e86d66bda0c6c710001a646ca6f9c73649b8ba445910606c3644bcc771f4008f38fac4f8068d47d03af02460abc1f14089b724d0f6a2e34bfb03e0737cfd124e627c4bd87898e62f3bb144b9e2866fb74f3a4888e5efcffb76354f2dc334296444875433a84921891a090ab03cfce64d73d9470484dc77c3d0c6009f755244be3c6bfd25cfc8cf2eb32e74233b4d399042a194f69daf13a2eb9613be3efb47c919fdabc5b5df5e2009caf815d377802d02fdf2a31950a384c2ae26c52b35d1eba0162e5ca96103ee0bbc398c7d8f6e8d2c42b9ee5968636e197c1fdead0d1213710a474aa9e4d31d6fb984e9d0a15d8fdafa2f210e7ce4e0d7cfba5ec4e78672605c0c0b8f368a5a685c555442eebb78f087019e5ae849aa8a28702a9fbc78e669f032d8c19fac1bb35f05930df01c80871bc606786a5ce80064de6c53c9edd10678093764e5985dc3d7ff20c4dce73e7abe285f0d08b9abc2bc9317cb36f8bcb5aa2371f387a5c531adb6b84e215d17f5d97df7e5c21dcf5cadfffc42a952f0c2ca40c2ccbccb3c6f9b0cd54f168887f032d90555662706058f474cfb097506e001f3448c40513cbe0d44bc27864f81a348a882025603c6837b4599dcd983c6a38445782321c88036a98c1a89af0dbf1f9de4ba2d32306ed98c5065d339b92efa85101fad1cf5e62b5709b17beef67fed06679e1af41e44c2810c32a8b28890c07986aa2bbae80b0849f2570aef2b0262e9757ca468afda33465c2c452f6b86f5975eeed2f74da0eef5639d16fae3c172800e7ea7e3c84193a56432f6987776ed9214f898b97f2b768d7e9f895118f18efef9382014a888feceb7431b6feac203033950a0d048209080d0cd5e90248e72c8408ea40824e5237f6a885846c907ef808eb01bbf5c896a45c6dca295f2b93e9d063c30d09163f46eca336d8e12892486d871c775a10d2c6c95d2c39c1b4a3def71a0ea3d9c132b21c9a788c1b3019e76f007725e96211300da623c5dbb0df054bf4d9cb945fdc0f88af60d8dcb8e6ea55d162e1462c1a8cfc5dc52d5614afe87840475c567c1e760e3c21bf68880480c5b0c3cf0ab5429a97439fcf8f6b15426b61c319180131d0d190bda91575c41accd75e1e61b367578f3005e18bcf6826c443c62da1ff18eed5c68dbd04b1d9e39e2bd40c3d78bafc855fd4c52420d1a0fef8e70be0e6c809f9b683c8c11e445942f438797ac44cdf11d4d84a933400def09be3edb11c47155dc5dd66ce569427c3ee5ad411f82b71cad5b94a08111260d0aba65e3f9067504d631119046abb0f6b51756186a5b55ee104697467fe72e85e8708c1c661703a1ce2f076f9803c1ea44f117d76ba4cdaa430e7a401ec4397ffa7bfb918b85386475d75e6d2e86ee3ca4bf1e25109400e860b848d55520caa14e1cdb6834a71c3f6884fa94d56844afd56b5489d5a228f9771d8e6694bf4df472fdb2ab6fab983c6b56bc4e95bc316c6d5cc2ccc660ba000bd3cc07a46bf7ebb27db61284a7dd2f62d43507a453275d3ed90a0c69c54d1760719df070ea87cdc6c5d1e1a9e777b62f7d68438ff89ec6e980d1eb0445f941f13d10dec6c2dafdee2a826543bfb2b4fe23fe7863a27f7c13dba28cb60c80770cc04bd646e4e8f03cdb00c337783d986c6709e1474d17956519f0f5db067478a6eb068cb61e80671bc6c3c33ffab3e0ebed8f84fb2d597ce3c6db01fc63f0d6a62d7eb6507d425e56116048f19ce3353d870c2cb381708211ec7d85653fb9f152564c2726265d1de3016c66546513c8af8ae546d5f4639be566c95fa414a6a6377b4241483b5bd598fb069540a4ca8283a3f628a841e423d10e233991400021c06c95946c0f251a3e610fe8cfa34aab96a5bb265d24720892a0943f525638fb766d5c007bfdc0a4833f7861dbb1cfd13dd1605c361efc85fce0f719f1193cc3c1cf1803e1dd07720c3c67c37bf1a077e2e105deb36293317310eb874650715cb6166f68bee16dc03c6aa8c350c3914fe6704e7050e48fc7d74fb0551b8dfccc88ed1df4cc481e4448f98d9d821b69099e0e9f5f49ccf1e54661ef601bde20bed1c4f07df3c40fceb03e1e41f7d724bd7e931d0f8f9014360e5fbe1f38fe81fbad30197ca3c01846064406574909d7f96cccbbb3e09c8b80ad1755ab980414cf1f1f21c15c576cfd1221b1a1764492655fabb080705072b33f0a9179e9e9cb2e961243e8f194a1bd5a8a7811db89fd0645ec7e24f229674b6654adfbbcbafd5229397cf5ce84f1e3c72bf898251507060f74cc361981ab4beb20608602c230491e1a495105863ac223f59a6c2dc8a1420428ea0e6942a04d4be95a68db50e7aaca750a68ff7da7c56e60e2c11b3a76cfeb171b1701e352a08d8b29402a83b9fb9580111d5551c62494f07ca01137c9fb243c5d33aacc04c02b80be2b3cf349459003fd28827e08c0bb2021defeb4f5086f18c0cb4b3c2e566ccb3aa78e99f366aa10bbc66c5dbb1b22d16b408a20d11f25d1f7554dc914d1af1e55586b85687e6dab9b5d1b48977f1d7f674c856572cfcc82c0bf5250010645201790f13917e0d9aa5f002f53a9eaac7949ba419bdd4975f85c05e3d9063a37882fcb2e8b2a4a2f4b32da06d87a2b602a234fa55a04fdd2f1f5dc5cf3607c747864d44f723c7c467db2e1a8b6d10941cf864bf8fa03406d03be5632f8e2fedd7cfaba99d31f1262ceb153de980daa739f711c6bd4702c85ef8151e6ce3ea44a87739308c75a9164d9d76ebc50280ec4fdbc507ceebae5468d2276142510bc7a3621e5aeb4cb5f5b0321f878a73546b0f3ec9ba4da824339ba48d5a4e2eaafd7148063727f43112f47ef2fff1e27884447245c4ca27125a19297163df5c381c03917261a97645545b00cc62679039dff0e7907dea3493e283144fd2a3487c1d32506136767921844e3541a096e244cc8d955debb7b841b67f4e345cb9d1d10df518f841d6be4d0701e619d906492150f512fc6f51c656ec6d186dd338d9c2ee7948b991bb449b517ec4ecae13bd0ce6a14be519f0a15f177a09d95103e735715413781728924f9f59b783c7c123093d01a8b2f977092c557f8f085f18fc676d2b70f7d72e23450a993648192076388a9e64e3c78ae0d8f7f63dcfa86759f7cd9df91e8f92eb58b2e720fd4a829421323b133e9ea59f5398b742defbde3e09f40254577599f0b35de690da9515250d21aa7d7bed425583342c007d8a8fae03527282c429426da2520172ebaa5ec5cf7dd910bd60f4d342ebe71c8d2c74fbfe3dd1799edbf633c8bc1d3e7c31f819bc9e099f00b27c4cf1cf91b4e8c9fef3955fb2295c1629163e807e0b1be68f9c58ea3c69b083a4a9c98c281ab24f1c229e4d490c084a196906b2ea84c71bf378e0bb6bd3be5c31afee6fe373c3fc1f39595103e9f87ac86e1fbf0cd6a1cbe41f823bca4c7c3bc1ff66c3c4cf0ccf39914be4111e441e381eb7ee1cdd327bfb44c88efbf2e9ab61abc4b6b98ea9d246696fb0a55f474f32012129e34d16675d2657f131059a2cbea2f8805dc393aa729b871ce33b2ab360f3c3a2c7a76ea230a26e5d24a5575ca0055d3d59478c10c3a3c16072019065ce1e06ffcc0eabf23420470894021018b272c9dc45a37d797715cfc014dc3d53b98aefc18c691fb395a5bc1d34dc451936efc18e6f41066b60d8749263e9d2eebc73144c6b3583fc21ade6663a8de8f418600c22c455abfeb515831076c6534de983a871b19f17b4e4060c3c5df35bdb3bc343346801e12ff709d217cf36653ff6d684735fcb9edcfacd3d7e77131049e9a6c45c1c6db84fb2fca25493b495b94095ff3fad2e16519f0e53699e16cbdf9ef086fd478c449128e86af49b2e6e3e19f3f24a476427c93b5f501be9fbcfaba331dce319238507381b656544d611b6cb8c408e17d1f1ac6c22f493ba291655f1110c7fc55b42a5ab77b72fc428bb283868c51902b891d3ca0e24ae99352d9748e8210429515a685c78baa30fe040909deb4610332e1807ed801df275b108e03356c299cc8fa7842522a3a366d1a6b6a1bdceffdc48cac5c45402a0ef5bc77501b1676d4b751f48dcd5526fe833f0af08603bc30c04b7cf01753ee2ffd20e2c64b5f843033dee2861c87c65c1ddeee8edb9f5b364a885537ce9fb969930248aa4bdc58cc8b8502510d91bbb46e602462df1d503f77f71d22fe0009c3b8e8eb39300239ca0f7a369e001f72a7892423a68d077d6162959979dd717cd97c717c03545c81aa5aee1516a4e26a64047934ec234c3afcc68f8703edac84f89abc2619bebb7b6c3f78d915724d7e5977335d7486b60c76f119d52871a06603afaa652a793a7f6ca8392149baa4ece90f1b2e74e564b65ebbc6f4a33a9dbcb4c7e3525a589d3ac4cddf2f20ecd0e2c62ecfaf9f5d15ab9e8ffc3552b863be102b3ef87ae32c50651185c6fb1d1885ae05ef1b8cdbc0ab4cc938be063ae0ec61c74d65adaad0b980dc9a95592d2621f5fdf8bc875b7f22c4213bba0cb957e55eca73cd701633629b8c96be34e03960b4f522bd99511c9e4f36e23d13ee519907f79e987270251bf19e09c6c5798d355e1afcf3b32097582904d6c1b8ac1efc7dcf897f95ebe41ff32a56a0771daa00c0784e990720130119d3c11859f78eaa493201824359a6d7c9ee743d7df2607784fa586d3adcd3c07af6ae3e56fd2d51712371f3383a61ff0d7152749f0a18ad13dcb0a9569dd159c2179867011e0a7e70c4b4d520be682c6611e409e280549ba52bf7dd6343c66780b79711e45e3b30275972e361c16e0fbe262121bed18b230b2bef12e2c3ba178f72efa4dfb162d3bced10c85a839932c0385e7505b4d1688e1933307e0d8ce518404d57d776024c6ca197b5a291655f111038288970a064200fcace438eefd1fa2221d2bb37abf9c3dffd1b830e9a7c4ae9a17be9c042083d9532c935962fa99d593ab59ffa0239482420387058534a0a14ed56a99a544c9ab02d3c4e736dd25d6fb8005c22b050bb12d2299f5fdcefd85b846832b4c5c0bcf31b1897d1466f1d5c88b1b748c2910bed79f1ef4a7a6197b088e47970e1559037d4681a35fd60f2a7e2600431e00e79cf6b09068f6df879ba5757a46fe45c57d29d78e9b377bc243754f5c6ca6995b0e16a1981c08d878484bc5bb6c3f390f61ddd26f9fd36eefaeeb1fed4bb4f97eb29342c745a4f77a4bcf4df19b167319dbbb79e470334d5ffe4d37fc7e049c2d11eda70877ec30c460311deb9eabd041fdadccba8e1886923be2574db4f1ec00f27c437e8022c824f8c8f82976c04b9613ce292992a784111e441e3c103404b1a87efa2d367747b79b910df144cfbf762c8d987779863ba7dbccf03e3d7f08228b4819084020c129e733c43c75eabe8f71b0141159294400ed8d836afa25c8883761d7aea5fb6c69eb2dd5427164fade045c4ea17f0c084847aa40c3cf04229ea5db5fda019338428fb7cf3524caf5e8ba94430e508729c18d701a947ea4e5035456222655e0b75186aa771fd37155f8a171c9f3784387ee23983cf1a2025b3c969a75fd025f62d1e98ea692e3114b11b03b9bb6e0e480c53496270e02f2e6c07e0a9dff31b036961c3c6c88103612acb32cb73701922dee3e0a9f7e480c43015e6976fc41276d079d94a75bc9153a4d41e8af15877d992c5932e1562c16d9fbfffdd0ef502cab67ba55e1321c100529448c02db20e52dfa06a8b245528ee9dfe479dd9efd9ae727da76c4ebb23fbcc04e3eccf8eacdae608f20ce87faccdddb825398afd5e0c84f1f3180c5b835f409cb30ecf8bf0566d2f82bc04da61c05f27fcc9e2eb3120d9807f18e01725856fb62f823c4383e7112a7d7d992454c12ea82aa10baa609e70bd353227191f0f8b13429e832b31bea5e11f87bae7d8077ff9f7f4f160abc5f55ad941d5d570052d12106ab3c067241c18af863901298d3b128e0ca81db187653f1bd15d0e7ffec269f76fdd26a9e2c591655f7f1dfb340c7fb9eed38e7d1ea05befbaf1844bfa834a81c79d58d3f5766809d4ef410dcf939b31d44438c27bd2cb0485c121028bef7384481b94bee1cc0e0d1ae7c2f0acae733605788d6336246f9c193cb49d446df81c6d1b4e627849bb2726345a12dee358f661a1eb861b1df15e0c92c7a8baa9ee7d318591b71f9806e9f82909226c28f44ae13a65d41d932d84b97b93111d4614379e4b58ca3a6ceef4f129c26ccb209b1ec39fad676f1e13dbfe087e0ef08d30bec66cb3cc481e940d37c17c35b8ff8cf84669feb212c14f1a5fbfad445f5ffe7da2e36bda27c375a7019fd38879fd363c1ed1002339b31d96656d39f3fb4b84f86f97c7ae1f05aa27be3ec9dbea13bdcd039fc9db0a6d1fe814a28d54dcfab5c55e967d2d81600d3c6bbc2aabdb8d271edfb6af44e180f4c2ec6ce10f6cc36cb2fce62fa64b6dfa5ccb6333e494fcd06a49e9d46239a89f55ae40dd208a6e38b0357de073e6474d5e3638b0195017409d0bb593f410e805e090ca231f6a49d8ba0ce993e7ba21670ce9ddf7b977e533b345bb666e3a787f6e28f576ce819902bc7c3a66e08882ef90470e0990060e330738b8a94c22f4020805c02b0078c8e13a002f1be03900af1fc083d131a9d0b8caccc0d965aaf69a59dfcd1f3b4788ef1efce22d37e7955b304710e604229515ba3fb2eccb6803411d72046e2624093517fbaaaa90942c4b9e5ff8f87629011f7ddc690b2f973db3beb1cadbdc1e879f0db63e5f7664d8c619600bf15424163ca7da0520bfc2bc490944a9140772152271dc20491247afaf03bc2a958fa7ff8e70862f9754c9f696789de52699838b2495007cfd39b8747c4d7790737c4ba85d00ed8c84f0837292f1f1b04833a0e019727055cc2d5bbe42128c31998fce78f2cfb10be9dead5059dcbc24ae205954808abe1ace354ab904eb95182134a2a35b3ad451d4b020abb6166a47ec65d9c7048422ad5132c0a48af2e06cdbace3dcedad843860c94157fcc90d04f4eb3eed584dc9e9885eaa361c98d677a122f74ef4832e3c2cd78df45ef3c682d71740a01837aa9331e946a89c40844e00001c4c494441548f563511103ec0af431d2729c44a41d008e8cf63fa79b27960fd8610e7e5dd34e5afcfc8a9989f3a6ba01bc9cc23598dc66538e84daa01cf58cb23bdd5f7a6acaa5e1658077eaf36ca545fe4b80df032009e03f0f483df3b386cf87d1ec0d3dbc9a6e93644bcd75d573d73abdc80635e7bf4a0e72546f56323c5b4119173830d59c5084715e89089a383e474987433f2aeaa697d20a3a18e742d5968f793fa0d3d52129a50e79473faf513222ec2fb3ce8474b357e487e0c4e249e0a86cf9b1a9781e24ef89d9a67ae82290960300cb6810446774bc737c96cb8088fd2aa9b549e0c7e10befc8ef012dd0943f0bbf80322c805e2c79d46b88a36d9f1c880effd8c500c5ec5e96597af3c5c88f71f7dbaf8898142ec7ca1f48b5d23142052ad628e3e24202a6da6a8445b0710125ad7a8ba02491a8de5513cd710d302a81df133957da4c2f2b98539f0392a3fa46835fbe5f7aadc2b69eb2745be5fe2c66570916f38a6232711d08e871265ee726daf3cac26679110bd1fcfbebef72dea498c4477534dc4ea54a8e1e0c038120c34a4c875507d910405dd2042801fd8896bfa1d7b3e0484c855ad5dbae9ce4fdd9bdf52e7a7df606789b8c86cd93311a7da493e3256570d7891de8e0e8fa98a7c11ea0655d170701b0dcac1956c72442f729cc163eec64946bcffd86e45e9e7cfc943ffb29a7198b4323ed23f56b37b3f303b29cf0c40eebd90a286447f4d7927fc81a312a3dd39db8f8e397570f7cce110f7e2b079f4bb4367b17189c6f797543c6341c56b52c1f0e4a449469037a092dc337c93cdc165c697c38736c00b7267770c714b368f0351e3da08156dc2f1f0abcad4f75b0b7e3c7ae65942bcf5a2ddfb61596f5bfad3573bc0664b2a299028785257aaabf5e729fe23ee8efed83b794034f608199f9fadec2309048bcf688c072a06f649dadef44f2dfff985e4d8da2c3fe4d63c5b7e38445c997a968873df0511d0a6fb007201a6a380c0e79d24cdef2244bb778f18786e0f210e3feae84d4d25e7b86ae3b7abbebd50bd0f250fb1595538e05658c79328354a1e79f09cc5fa63196ae061425d549df206d4b25f7f98611f7987241ccd1e6bf9d23b6fc7f0bfc6bd09ce1a692982d98e386d8585973e3bd6ef38ce477d6e037d2ba1cf15073412daed54d8a4275930d54891d07b65c3b89690224f00bcf3005e4b801706780efc3a03e0091d3fa62210d00f0f3fa1e3c7eea7b0e17e8d0ce20033a09731bc4b5bacbf64865c4fe3a63e71fd9beb152c727384ab91dd24746ea9ac84fa23a8f17bf072418e8e6c2290d9a01eee5b201516f6240c354820d65a2901bfb7e02337434297bb8f1fed322e299bd2569d7a6aacbf5ba0bf27417fd702ac0ce8979a37baaa18dafe7156e3d142cc85b68297cbe0d9d02e61f06d9d538ee3c4117e18debe36beb77b8a6f9c4a2a0cbfcb80df69f01bc037231e5f092f17da1abc24f05d0bcf69f88acea442cdd84bf8561c54b1eb93ad35df3d23c4c42b9ffb6fbe3c0767df38615aa11c89bac2da372a4f56cfa031bcf272a8c1468b2a2bba39b55c7f9eaed406c983ae1960f11e941b1025e7b0f899cbbe22206b55c50f54aae1407603fd36ce5bf5df8a17e4869b7fc2ea56f32547fe4adaf893dc3cf799a02ac19bd73c115e9125aecaf1bc7e6cb76afa5c8bd37af796cd6f7b8fe8305872a8ad97dd33e75a79386cae7eb60e0e882824d32333b30df88d66fdb0597f4aa0ee9cb89f2120182e0169b1bb75852be90c3af39ec71e7958f6efb5d4290fb8aa3557b4ce8bc33b0b44e1525da71ae83668f2563224eff379bf08dffd0628723b002f1be029afae71e0d5956df09b174c0565ba002b0bf01d872a02a6d20a5069543d5df1c98f438578efdc27434f1f283793a89a500984826c19c8d1018120f747cc828c6ebb702f0ca9acd05f1e37e44dd0339bd5c81001d10ca1a429d77575a4fc964552223eb453f727af7209d349e2fa1603ddfe820d299bcd9bffceed0c18970218171c67d5f6bcceb40baa8c49128bc88b4d87ef8f7f2881b682674892484917b97b31c3d7536922c3e24b9298781d9bf035dc116ec2374e15aa8f8747a8d4fa32a8b812b8cd17c17309c763d103d35b3db750128ebf8fb8ebdd1be4e1ffef1dcb773daf3acc250db2c5c14da74450eed63f47c607555c787f0dd970212720b9e9a2a4910bf55a56ff6c655f4b203a6feb3b8051a5e346924746d7dcba4812920e83babe78b514c9acefad1db1886cd3c499379e5ab0a0534fbfa859e55172223b457a2de9fa8dfc608bf871999c98adbbd76f2d03ca4d8403f1c40e00a123c20747381188e9ac4649a3ab10170eb975ed09238438ee8133ad31f2fda1d294f3738a85d9f6309a38fc5ed08f30f4836f1085add948e7403b57c1838ba54c07465080176ef42230daf6f319156d784a1dfc4cf7eedb881ebcc457bc06300675ebaa1fdfb64d888faa47e53f9a2e259089eb5fd90ef7bbd4cc5775d58150a32482840475c84860f09e179438d046862a0030c247bf861a3839ea890d6dc650b846f5b2755b46b917f6742aea1d71df9b3eaae91167a7094f7a4932dbb037cef0b6305d58a534e33970419527b1e23c16a8e78c362907e021e140f8b6d6363318050de34bed5c6823fc0c866f4663f025781ec391db20bed90c5f6e7c2f315c5065769bd7e0572d2e9fb74eaefcef7a177ef0a29ce79967bd37eaabff516fc0839e6e38854040b46de07ae4711d14df012a2b6474284d3bbbb08e240e18005dd92f7efec0682afb9880709b001192d150838ac7dd78dbab373eeb0ef89107677eb6fb39b9e1ea9b7d73b69bf77e2d898ab15fc771140d6e3c1ed8967a54faca0cf99e0ed33a77bae023f99e493dffe3265dacaeaed8b25a1e183b976c5982ba47c28fa74219cdda923368726bf359a9c70a3170c4b067c352d239befaec7f3c2027b669a4e588a7fe251fbada6ad9f1558d3382b1600b3a0b16b05f62009c92f456f2e00d03787989c7854b0cb8710c0158283194ea91b7be48617ffc0a124001f0543f82af7885a29eafdf56d7ad5c4a8c859fbefdcc637f1262f5b8ef66fd78bd7a0275c1d540389063ab423f79241ce82f8f5e56e8fe88de2bb821d1f88812ea5ca81dbd26f76f201cb46e60bdbb12e8c6b12b2f5c7a8f94b05f3ea1c9204990ac2facb456178b78d5870db0800c41db81b6c7308d86e7543b0bbc14e7f99c0f54db8bc3d0e1d33e22950bc0c7f887c632180d1b9b050ff84c94665fc39718435cb70c3e6314397cbf338603fdd4e163c4bbe72596110fdfe42556dea6ecc3e27652d2387c7ac757e53a99d2fe8587dceb017ebc6bd93f7f04152a19b7c1890319962a8c244723394a1ca05245c281120a8783aaaa08dc881a05c9c3678b43e71f5bece362edeb17c06be03d3c4e03931ea681313b1db2e8ba92c785b7dc367f4c441efcebd3c79c716302a0e835918f1c056e3cb0b4302f1df937f6bdc854df5b4ba03ddd4a738d5091acda794bffe306dfd43ef68d94546a5b57d72e7545c86662612cf9e3fbd1735ddd64ea75e9d9ad1748c2715fb3b4e3a4089a529ef6f7134e907d3a36f4524f0bdea4b0092bfc8833d217348f1c1fa9ae26153d415564764b74183c1b5af9f09c7aef48c0a3a7cfcdd186e7f2015b354e4101592381e3ed0957a8261f399db81f23ad6206cf4e342e91136bcfd875bbe4ecc6bd3ffe09294b2dba67fa8c15e025558b374c822451b156d5e570e0574c55352728da8d9022ce888e81573ced35b27636d4d84324206ae42969273a6de0f5022ea332a0e2baa7064bd6a0d5d5ed36bf005e355a31a878e2ae12566d1ce791c0680cb362b7e1906dc3e78d67501999e68d477c0b7695b23f50af61f8843f5b7741f8227c5b87e7c13748508dc5d7a25974e06f0c5eeddc9aa1dbde938ced811b577dfd8410cba7cd9d3b5dceefe2dfcf18ba0a24803a8c2fc2b000583f64ec46a70dbc89146d17d3f43649c4681c47af2a804757d0a2b11c53eaa0713cce89c3ebd9fe28fb8980708e8d3878880b41ef28370bad5b9acc16e2a4d0f965279e28c4116d7a9e3b65977039aeacd08c04b0935dc818998d777af7b496a8e78c0bcd0678c87939f07bd5ce5407a0dcbe08af51073f7172f970f0636ea825a45977183c1be025de807c1cd086b4c41adfe0b8e081e1c1b313e29d0907fd126b493cbcb87ee804d10e509564423f96f8c625d6ae3bba7a52694f213e7fe2cd371fffa79438ae5f70c5fa6eea41221c58a3bba38af116e519d0863ba3c9f8788ffe3b525d419c10110ee6b54204841592aca107c418a1f7df59aa4e4f97df6d4fbdacc59d52527df0cf47bcbe5b12971f9b34397b5642b0e1186c0341250913d7df12603c928fc8ce0f800f8c888f21083ae8f708de1ee08bed86096192f856f7ad18b16eb41065af95e62d1c24c4da9edf977cf59510dfffcda95bbe5ccefdb0fa1f78ba7fbad707af65c0005538e0719dd1454e6cbda2ea94240cf41ac414242ce0b50e08d1af877060d95f04c486d7e5eb3512129f24d244d5cde4c171f6eb43bfbaf926210e98dcf6837b6b1b78879f6381cf6921ab8d96091c1bdb781e8e3e0edf8196612383e4b3c4d20e7e12817df0020e7edf01dcf00649000fbe050e3f0c07bf6ddc70221eef2424869e498d8b0f1e7bef4838107ad281107bbe7c6259ee7229ea7fb2e3b5839f1d21c4c693579f5a5aaa20d2d5c0b82181d3ab0209a37c34d4cde1f37bf4e790f3abe191bbe8b6cb7204910ed916890b7cce2511cc029d02eb192591a6d708d17e52e72eedfa0b714ad5a54fbd7fac7c664cea573dc618e0c7dec118172eb10e03c685136ce3fa0b98b7b0228b494b9241490d6d80e749503640cd07787663f0956d0bda084fdb17d173c4e31139af911935f76dbb45ae99ba9adc2d72c757e6eccafba1ab9428c4c6c3dc388c1f1e5d72ff324920567fb160e5065085f20be47c17ce2121e1f7f9b01a1916f2ea83f54636b74ff59a22cf791a76765f8def7e22241c36d48ed8cf657f11102c0ebc16365c0809c9c3aa46498436dc89aa6ede498801cfe755e69508d1ca6e97769f7b80f4b7ee4bf9d2fc2adf42ce018e2d7fcf2406d9b2e1398535a492900b3e1fe0393a3c347a82ca2ce8e0cf018961fcbe95188c9ce71e4a0cc62ca8744018086026a962b2dd0db161c1aac953ee1062eafd2f968cdd2237d55335a328391c120e4ce980c645201095a09aaa28811a545864f3c0da94b204bd590ae3474a78571507dc1f432a5a6c2363849208aceb26c818fd8f109dafeb73cae12b84e8bd38fb8a172f97cf1c9ebee1845d0dbcc42f61dab136635ccceb5967e37ceb399091311026801f7db07eb49b4266e7275b2f9e7f913ca85ffbe9ab457245576edcf5c3767990d71d53f38d6b634c7ba7c989ee78a4ce6b729b2b99a57d956e357954b64f4b3fc35561a7be9a36d3d540847e48f92e458e636453dd37eebc45fe5377b73bff7503aa8b5d9564ddbdb5396ebb6af0ee27dda499a57f5edf7fcb9f25c3f1fdea66db24618e4cab1b42778023c78e71122ca54784a5efaf67f7c3d0818e8403250396361d3f4755a9ef9e8ed3d8f3a7eb35bfbb9cd6a549e2b0a176c42f54f63701b1e1b5b8e48157456fac14d86828fa37295375b335aa766d23279f77f16dfde5001f36bffb09fffe56c23825b42866943415cfab44bd3570e3b1837fffa98a748981ebc23de3a281c3f71dfc98fd75b07a6fa0c460033cc3c1cf556806db4b902a11fa119952fbfd8e51422cc8f96ce9c85e427c73c9b4260b2f553fc4540cb54cc4279515c66fa0311209489eaa2b5bc2ef180748120712103c60d0680e88373a4b293c479208ae6bb489c4a9b2dc8237663695758b49ad171df0b41059b75df5dcc30fc9cf8e6bd9fad2850dbc0bc7196d5cc3603ddb64fb53d824cbb8980807ad8bc4b6c5e898e83dee3cfc74cbcaac09b709317bf3fbf77e2c39ef9a77ab5a2381a7ecd8a822c403d1a48a0992f84c05558dd0539a3f06bf9ea9244d0403e3c37c3754627f0c81a73c7715111aac9150601bc7e30b563fa8f7e397575599cafe2620581c783d974450878c9208184b9b422ea2780eeea892df3dd6ed2d218ee973ea8dcfb595bfc94e7bbc6bd706de693389616f5545392213e029c2316c2f554539f0fbf12431c0d3c9a98a3cce9071f8811243e283df67bc25788d3c90b00001ab4cdb55b2f26521a6f71b33f8b94142ac5b5b7cdf46b8cf05ef6f41af28ae2bae42c90309c7eff436facfe3e7fc821d9fc4f173e992e179eab1a32a7e23661a787fa5dfa66a97d38ed510b0e8aeeb339ddc19d77516a2f5651deebcc3f502cb12592989bc253361fdf9254cd3fad3b08c9b371b7e8d8c87056d058fade7dae6d54fbbf335ebbcf7224f0e940464d0ca8f36429c0c2718940980dfe5cd6e7e345d1d1dc859db7ad3a77a849a130eba629a110aba480c250f7ed531339a930481eeb568f4fe34f1f344a8b8c4838ccc170ccf30eb8f2d7e65e5972220581c55190989ba5849a44352bb74b8e33c9ddd7ddef42b210e38ba6daa1b887852eb0beaaeee2844abefdb3d79ed9112f6ef43a52d2ff0bfda7830db49aaa08ae1fb9e012a013341417836c0432fac868dfb6663a52e998c037883c17b2a799db80df06036e0bde3008fc181de2fb1bca9e5cfee9cb0e43f42ac7867ee9913270a316fc347b316b869f41df1003f68c8fb84491ca4b262de2adc8b8a9e0337dedaa374f868f44482810705cec0cfe62f0ff07c84049c455220a0311572b5e19dfd2499004171d773ac2dd779ef36d9d13edb85e8d4bff7c45b8f93cfa6349b7dd25d09df1d56ef6ea4d7958111e0eb7973b8e483896592d9bfe98d4563c7aa5fd2018ac6622018949b099358a24a0725402e8920216964c474b430f1f3bed433d846c28504050809d9c0b8ea88db401ed09fe384019faf636d7e11192794bcdfbe6cb98ef895965f9a808455e5db70701422e7950a3611748f4c3f1b6a20204d58ed66b76d1fca38b6dd22218ebd7ac0ca6b5e17a2e5e96dbebea052c2fe38e5cd56d76b38d80a074b3f3083365e26f3ea1a0c9ca07923db002ff1c18f5e35681c35d9364c07bf4f05e56b3b0c9e0df0d4f7a05a6bc0ed1302fe40e2428ef4b19a9ea512e3ad9ffc9839e32c218a2f9b79fd74f98bb5cdbfbf7f03dce4176157c6e2c153fba3aa310090a7a9f6a5b166c9e3f84155cb6e1c347a55617b5fa9046c55914a0bf6194a22b4aed1c88e5e88404888419aadd74de5e77dcf1ff8e619723c0f4b3d6ade2d9240a786d29b76a98e7bb78971e15e7f06e378dc7a89fdbeaa7877c6f24385f8f0af2fbcf7d0003987436b3f22f767640018c1e7354a8475ccbb881376ce69277dd5aac37e8f6d4e4870fe1921a9e777e1f7d7db51d6f6d559ec775c1565221836c3b7b1aad35fbcfcd204048bad2ada700ed4209c23c7461b0f75caff50751ab8ffa69fa36abef15cf7e096d7b4296bdd5d88eeb3fbbdd2e72a213a0ce8f2e4f9e7cb4df942cb97dcaca9a11742e9cd9b37a8ca11f1d8c5490ce3e1533cf88be27e9dc87dd70178d90c5e36c073e0536d63d3c1efb36518085631b47b1a545c49aaa0eaff50bfcee520abca77b75c2125c1d259eb87cf6d21c4bacb8bc38bda09b1b2fe9bc37f7073419d1c9d100952013077c71a20e4d518498e5e2aa60389130ae6868b1ca2cf5f9e7174fb4d97eca88aac6d7f56750ae43e42552d7921028344eb1925136cc7ad6bab87f559b3c992efb8b17fc7e3e43ee8d0a1736d7fd9df961fb69978861ce7d4caf45d47ac4e5e051ab7de62a742746474b4eb7cf0e584ff5e7aeb07426cbc7ed588cd2079d432af218a6b401b15c63540bb0a02e55045c9bd8be88a602d8d6123ca70f63bd6364a24cc1642073c12166e8b40c26070f32655145799fdaf2118bcfc5a08081647557cc385e046ae14f0d622ef16e4e0b0c68d0684c5c7d1dd0e6dc829e3ba0ba7b6489bdd649610873f7ff42387ad10a26ddee157674889a5e9a52d7b1efcbc7cd79d69fd9a3f21eb05a9bd5db76271ae382d66244d17b70b298358d789d6966ba65e635d163357cfc4ce58eabf6fa31fbbbc9e351d7d73a01c27ee73793df97b554055261ea68d1d3b4e306f98f8a3a545c14868f00d40c88354227f1400d1528a93e9640c8d7d6e5d690d72554c91eeb52fbbc6ceba3135356e246cedef6aeeadb85b888a93767e503641884da135976ce821c44fafaf1ce0065445cba2371087851bcaa0cb454242e9f499b7091110943ce0ae7a327aa34a04dba7eb9f73a324e215015b0aa620f1795519541efbbc38aab2c01d3934186a201cb89e7d9209aab8205e240dd63512942693a18608658ca3727f77c83fbb7ed05eaecf76e7747a24a3408803fe79d0968e574bd80fa51f71e005f25d57a655bb0c53a87d685e6c9fac1617c5d6e36a71ad0b6377687b97b5f2bfafaa26f4f902c697e21ed046850404558ba86a646ed3e8d6ca0908a98ad841baa72a459f0462806bb2b9f822ba79cd0810ad2b0e2fcaf037e0f3db2fbf360282c55115b78dc091e88b64a774ed2099e0c6a30d88f524f81c2384e1ea5b4af3ce3842dcd0a87a203ca08d040efc9de880301d509e1403c54efcdc2f566cbda9df151827f2b31bfac81889124090dba3e1c6359e769d7bbb90b19271aef5f83ecc5d05d996f906ffc5c61bf0b0b6400d0c11caa674632632486c5d23e1f0a970e1c2b42613a1fd28fb1d3cc709145d5b10d26be6f6e071dc502301a13bb7d1c681b6282424a8620406006d56e4ccc024443a786df6fea8d8b3e2c0efb3d8e700df47580ceeb151ae5ae370b9e483bfe34e00765258ff064bea2f8d80a184551505fffb7a68a36da41e099f03356c083ad06003920a05366064a0aae9c22048934c04086be00029d0110906236016a45ba65c48904c11d2047a0707271c581219437fc1421bc881f69dd0fe5055f519f0f965d0462323777fc47187f18d407a6a1e7055cbef35b8873d87aa29ee1f8fb60d788e0e80c5806f0eb47f2dde2b8eaae8a081839a0e1a94111f60cfc37a8b02475f0f1c7e3decdb08ac331cdfda93549d066d92d4611e8880601be0e3bab6eed4d18ef685f7fd0dde8304e478a8e1fd35f03e5235a2c4c19c1de8aa55945819e72eee177b548c84e633f61caeef0758db81f619faf74420f0f3fefae7bef7ffeadc6cf775f9b54a2058d41546640be1b612baa0894b26c8713149220db262a68277174a22292c9091736c248120e140a328e0451120889f8960fc468a89e38a425aea7abcc9112513ee478fa91e78ae206ca36482de52dfb1e7b0662a325299e1c6e64671201ce2661dff5f5d715485f122dc7984d617974cd8ba4e05556c1aac677e711aad6b6088683da35718638cf8b50bf52c4e069d2188016092087762e0dffb22aa11be2db4b2c792475071003e974cd8f77cddfcff235134b6fcda090896b0aa9879db8b0076544d073c2728b86160a3a5409a6fdc70c499618dfefbb0517d2a2cdc70600c251516120e5b47ffd74a507c1b83d5dcaf9e0e6c6efb084a01c1b2dce24152f72c7c0e048908467ff67ee61f6f348a23e108881cffd594b0aa685ddbd0b6f49ae2499071428282eb783bb471fd1a6c2bb4aeb9ea0a094936c30f19049c4f1637c1bdaa7ca93d3070ee741d8e31cea1b1c56175234bd0faffbf12547e2b04841747559c83f3d94c70232201818d4784856d241fc1e01b0d37f4437a5b200119ccf0b493e9ccafa038ac86c28dcef5ff85cf17e9df932d020ffe00b7c7084b3181924994fbc9f33aace3f98bdb367eae1256156790b05f5c32a15429b85e0d0c135fbf21b6fe79c4bcc5ce036e1ce671124448b8a4c9920e22e1f125a774f4cff7f8e076f6f2f7ff57f6b0fc56090816aee2823679baf7841a0f7eb8e8c5ba03da904f9f36144814a1f17a9b366e2fd606b74a52619da2a3479fffca4b14dc33c558f6c538fdfb285c901385c0309f3be42068ff57afebc71a3e8700d1e8013a1cb26160bb98e1395cfffc7f5de10c098c0724bbf1d61facf310ae532619a3b797f51eb4c71bbe5f92f8bd34efc83030b757f2765bc83e8775500fb632b84d9f728b91ca2a47fc5ff94d97ff170000fffff898dda83e6a16740000000049454e44ae426082', 'image/png'); - - +UPDATE PRODUCT set PICTUREID=10; diff --git a/samples/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql b/samples/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql new file mode 100644 index 000000000..980d37d43 --- /dev/null +++ b/samples/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql @@ -0,0 +1,81 @@ +-- Autogenerated: do not edit this file + +CREATE TABLE BATCH_JOB_INSTANCE ( + JOB_INSTANCE_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_NAME VARCHAR(100) NOT NULL, + JOB_KEY VARCHAR(32) NOT NULL, + constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION ( + JOB_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_INSTANCE_ID BIGINT NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL , + END_TIME TIMESTAMP DEFAULT NULL , + STATUS VARCHAR(10) , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED TIMESTAMP, + JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL, + constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) + references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION_PARAMS ( + JOB_EXECUTION_ID BIGINT NOT NULL , + TYPE_CD VARCHAR(6) NOT NULL , + KEY_NAME VARCHAR(100) NOT NULL , + STRING_VAL VARCHAR(250) , + DATE_VAL TIMESTAMP DEFAULT NULL , + LONG_VAL BIGINT , + DOUBLE_VAL DOUBLE PRECISION , + IDENTIFYING CHAR(1) NOT NULL , + constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_STEP_EXECUTION ( + STEP_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT NOT NULL, + STEP_NAME VARCHAR(100) NOT NULL, + JOB_EXECUTION_ID BIGINT NOT NULL, + START_TIME TIMESTAMP NOT NULL , + END_TIME TIMESTAMP DEFAULT NULL , + STATUS VARCHAR(10) , + COMMIT_COUNT BIGINT , + READ_COUNT BIGINT , + FILTER_COUNT BIGINT , + WRITE_COUNT BIGINT , + READ_SKIP_COUNT BIGINT , + WRITE_SKIP_COUNT BIGINT , + PROCESS_SKIP_COUNT BIGINT , + ROLLBACK_COUNT BIGINT , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED TIMESTAMP, + constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT ( + STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT LONGVARCHAR , + constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) + references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT ( + JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT LONGVARCHAR , + constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ; +CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ; +CREATE SEQUENCE BATCH_JOB_SEQ; diff --git a/samples/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql b/samples/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql new file mode 100644 index 000000000..f34cc3507 --- /dev/null +++ b/samples/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql @@ -0,0 +1,132 @@ +-- This is the SQL script for setting up the DDL for the h2 database +-- In a typical project you would only distinguish between main and test for flyway SQLs +-- However, in this sample application we provde support for multiple databases in parallel +-- You can simply choose the DB of your choice by setting spring.profiles.active=XXX in config/application.properties +-- Assuming that the preconfigured user exists with according credentials using the included SQLs + +CREATE SEQUENCE HIBERNATE_SEQUENCE START WITH 1000000; + +-- *** Staffmemeber *** +CREATE TABLE STAFFMEMBER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + firstname VARCHAR(255), + lastname VARCHAR(255), + login VARCHAR(255), + role INTEGER +); +ALTER TABLE STAFFMEMBER ADD CONSTRAINT PK_STAFFMEMEBER PRIMARY KEY(id); +ALTER TABLE STAFFMEMBER ADD CONSTRAINT UC_STAFFMEMBER_LOGIN UNIQUE(login); + +-- *** Product *** +CREATE TABLE PRODUCT( + dtype VARCHAR(31) NOT NULL, + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + description VARCHAR(255), + name VARCHAR(255), + alcoholic BOOLEAN, + pictureId BIGINT +); +ALTER TABLE PRODUCT ADD CONSTRAINT PK_PRODUCT PRIMARY KEY(id); +CREATE TABLE PRODUCT_AUD( + revtype TINYINT, + description VARCHAR(255), + name VARCHAR(255), + pictureId BIGINT, + alcoholic BOOLEAN, + dtype VARCHAR(31) NOT NULL, + id BIGINT NOT NULL, + rev BIGINT NOT NULL +); + +-- *** Offer *** +CREATE TABLE OFFER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + description VARCHAR(255), + name VARCHAR(255), + price DECIMAL(19, 2), + number BIGINT, + state INTEGER, + drink_id BIGINT, + meal_id BIGINT, + sideDish_id BIGINT +); +ALTER TABLE OFFER ADD CONSTRAINT PK_OFFER PRIMARY KEY(id); +ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NAME UNIQUE(name); +ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NUMBER UNIQUE(number); +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2SIDEDISH FOREIGN KEY(sideDish_id) REFERENCES PRODUCT(id) NOCHECK; +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2MEAL FOREIGN KEY(meal_id) REFERENCES PRODUCT(id) NOCHECK; +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2DRINK FOREIGN KEY(drink_id) REFERENCES PRODUCT(id) NOCHECK; + +-- *** RestaurantTable (Table is a reserved keyword in Oracle) *** +CREATE TABLE RESTAURANTTABLE( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + number BIGINT NOT NULL CHECK (NUMBER >= 0), + state INTEGER, + waiter_id BIGINT +); +ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT PK_RESTAURANTTABLE PRIMARY KEY(id); +ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT UC_TABLE_NUMBER UNIQUE(number); + +-- *** RestaurantOrder (Order is a reserved keyword in Oracle) *** +CREATE TABLE RESTAURANTORDER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + state INTEGER, + table_id BIGINT NOT NULL +); +ALTER TABLE RESTAURANTORDER ADD CONSTRAINT PK_RESTAURANTORDER PRIMARY KEY(id); + +-- *** OrderPosition *** +CREATE TABLE ORDERPOSITION( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + comment VARCHAR(255), + cook_id BIGINT, + offer_id BIGINT, + offerName VARCHAR(255), + price DECIMAL(19, 2), + state INTEGER, + drinkState INTEGER, + order_id BIGINT +); +ALTER TABLE ORDERPOSITION ADD CONSTRAINT PK_ORDERPOSITON PRIMARY KEY(id); +ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2ORDER FOREIGN KEY(order_id) REFERENCES RESTAURANTORDER(id) NOCHECK; +ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2COOK FOREIGN KEY(cook_id) REFERENCES STAFFMEMBER(id) NOCHECK; + +-- *** Bill *** +CREATE TABLE BILL( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + payed BOOLEAN NOT NULL, + tip DECIMAL(19, 2), + total DECIMAL(19, 2) +); +ALTER TABLE BILL ADD CONSTRAINT PK_BILL PRIMARY KEY(id); +CREATE TABLE BILL_ORDERPOSITION( + bill_id BIGINT NOT NULL, + orderpositions_id BIGINT NOT NULL +); +ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2BILL FOREIGN KEY(bill_id) REFERENCES BILL(id) NOCHECK; +ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2ORDPOS FOREIGN KEY(orderPositions_ID) REFERENCES ORDERPOSITION(id) NOCHECK; + +-- *** BinaryObject (BLOBs) *** +CREATE TABLE BINARYOBJECT ( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + data BLOB(2147483647), + size BIGINT NOT NULL, + mimetype VARCHAR(255), + PRIMARY KEY (ID) +); + +-- *** RevInfo (Commit log for envers audit trail) *** +CREATE TABLE REVINFO( + id BIGINT NOT NULL generated by default as identity (start with 1), + timestamp BIGINT NOT NULL, + user VARCHAR(255) +); + diff --git a/samples/core/src/main/resources/static/index.html b/samples/core/src/main/resources/static/index.html new file mode 100644 index 000000000..6d3ae41d9 --- /dev/null +++ b/samples/core/src/main/resources/static/index.html @@ -0,0 +1,20 @@ + + + +Welcome + + +

Welcome

+ This is a test! +
+ Services Overview (CXF) +
+ 1. Table +
+
+ +
+ +
+ + \ No newline at end of file diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringBatchIntegrationTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringBatchIntegrationTest.java new file mode 100644 index 000000000..647dbc877 --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AbstractSpringBatchIntegrationTest.java @@ -0,0 +1,95 @@ +package io.oasp.gastronomy.restaurant.general.common; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import io.oasp.gastronomy.restaurant.general.common.api.security.UserData; +import io.oasp.gastronomy.restaurant.general.dataaccess.base.DatabaseMigrator; +import io.oasp.module.security.common.api.accesscontrol.AccessControlPermission; +import io.oasp.module.security.common.base.accesscontrol.AccessControlGrantedAuthority; +import io.oasp.module.test.common.base.ComponentTest; + +/** + * Base class for all spring batch integration tests. It helps to do End-to-End job tests. + * + * @author jczas + */ +// @DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public abstract class AbstractSpringBatchIntegrationTest extends ComponentTest { + private static final Logger LOG = LoggerFactory.getLogger(AbstractSpringBatchIntegrationTest.class); + + /** directory for temporary test files */ + private static final String TMP_DIR = "./tmp"; + + /** scripts for all tests db setup */ + private static final String ALL_TESTS_DB_SETUP_DIR = "classpath:AllTests/setup/db"; + + protected static void login(String login, String password, String... permissions) { + + Set groups = new HashSet<>(Arrays.asList(permissions)); + + Set authorities = new HashSet<>(); + for (String permission : groups) { + authorities.add(new AccessControlGrantedAuthority(new AccessControlPermission(permission))); + } + SecurityContextHolder.getContext().setAuthentication( + new UsernamePasswordAuthenticationToken(new UserData(login, password, authorities), password)); + } + + public static void logout() { + + SecurityContextHolder.getContext().setAuthentication(null); + } + + /** + * database migration helper + */ + @Inject + protected DatabaseMigrator flyway; + + @Inject + private JobLauncher jobLauncher; + + /** + * @param job job to configure + * @return jobLauncherTestUtils + */ + public JobLauncherTestUtils getJobLauncherTestUtils(Job job) { + + JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils(); + jobLauncherTestUtils.setJob(job); + jobLauncherTestUtils.setJobLauncher(this.jobLauncher); + + return jobLauncherTestUtils; + } + + /** + * setup run before all tests + * + * @throws Exception throw by FileUtils + */ + @Before + public void setup() throws Exception { + + // setup test data + this.flyway.importTestData(ALL_TESTS_DB_SETUP_DIR); + + LOG.debug("Delete tmp directory"); + FileUtils.deleteDirectory(new File(TMP_DIR)); + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java similarity index 91% rename from oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java rename to samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java index 99c1835f7..1acc4674d 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/AccessControlSchemaXmlValidationTest.java @@ -1,56 +1,58 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import java.io.File; -import java.io.IOException; -import java.net.URL; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.dom.DOMSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; - -import org.junit.Test; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -/** - * Class for XML Validation Tests. - * - * @author jmetzler - */ -public class AccessControlSchemaXmlValidationTest { - - /** - * Tests if the access-control-schema.xml is valid. - * - * @throws ParserConfigurationException If a DocumentBuilder cannot be created which satisfies the configuration - * requested. - * @throws IOException If any IO errors occur. - * @throws SAXException If an error occurs during the validation. - */ - @Test - public void validateAccessControllSchema() throws ParserConfigurationException, SAXException, IOException { - - // parse an XML document into a DOM tree - DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - String xmlPath = getClass().getResource("/config/app/security/access-control-schema.xml").getPath(); - Document document = parser.parse(new File(xmlPath)); - - // create a SchemaFactory capable of understanding WXS schemas - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - - // load a WXS schema, represented by a Schema instance - URL schemaPath = getClass().getResource("/io/oasp/module/security/access-control-schema.xsd"); - Schema schema = factory.newSchema(schemaPath); - - // create a Validator instance, which can be used to validate an instance document - Validator validator = schema.newValidator(); - - // validate the DOM tree - validator.validate(new DOMSource(document)); - } -} +package io.oasp.gastronomy.restaurant.general.common; + +import io.oasp.module.test.common.base.ModuleTest; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.junit.Test; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +/** + * Class for XML Validation Tests. + * + * @author jmetzler + */ +public class AccessControlSchemaXmlValidationTest extends ModuleTest { + + /** + * Tests if the access-control-schema.xml is valid. + * + * @throws ParserConfigurationException If a DocumentBuilder cannot be created which satisfies the configuration + * requested. + * @throws IOException If any IO errors occur. + * @throws SAXException If an error occurs during the validation. + */ + @Test + public void validateAccessControllSchema() throws ParserConfigurationException, SAXException, IOException { + + // parse an XML document into a DOM tree + DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + String xmlPath = getClass().getResource("/config/app/security/access-control-schema.xml").getPath(); + Document document = parser.parse(new File(xmlPath)); + + // create a SchemaFactory capable of understanding WXS schemas + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + // load a WXS schema, represented by a Schema instance + URL schemaPath = getClass().getResource("/io/oasp/module/security/access-control-schema.xsd"); + Schema schema = factory.newSchema(schemaPath); + + // create a Validator instance, which can be used to validate an instance document + Validator validator = schema.newValidator(); + + // validate the DOM tree + validator.validate(new DOMSource(document)); + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java similarity index 80% rename from oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java rename to samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java index a68acad18..f2eebad9d 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/MoneyHelperTest.java @@ -1,73 +1,73 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import io.oasp.gastronomy.restaurant.general.common.api.MoneyHelper; -import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -/** - * This class tests the {@link MoneyHelper}. Especially summing a List of @Link {@link Money}s. - * - * @author mvielsac - */ -public class MoneyHelperTest extends Assert { - - // /** - // * Test for summing up {@link Money}s with other currency (USD) then default (EUR). - // */ - // @Test - // public void sumTestUSDList() { - // - // List moneyList = new ArrayList<>(); - // - // double[] amounts = { 10.0, 15.2, 47.11, 42.0 }; - // double sum = 0.0; - // - // for (double amount : amounts) { - // moneyList.add(MoneyHelper.getMoney(amount, "USD")); - // sum += amount; - // } - // - // Money summedAmount = MoneyHelper.sumMoneys(moneyList); - // - // assertEquals(MoneyHelper.getMoney(sum, "USD"), summedAmount); - // - // } - - /** - * Test behavior when passing an empty list. - */ - @Test - public void sumTestEmptyList() { - - List moneyList = new ArrayList<>(); - Money summedAmount = MoneyHelper.sumMoneys(moneyList); - assertEquals(MoneyHelper.ZERO_MONEY, summedAmount); - } - - /** - * Test for summing up {@link Money}s with default currency (EUR). - */ - @Test - public void sumTestEURList() { - - List moneyList = new ArrayList<>(); - - double[] amounts = { 15.28, 11.47, 4.20 }; - double sum = 0.0; - - for (double amount : amounts) { - moneyList.add(MoneyHelper.getMoneyWithDefaultCurrency(amount)); - sum += amount; - } - - Money summedAmount = MoneyHelper.sumMoneys(moneyList); - - assertEquals(MoneyHelper.getMoney(sum, "EUR"), summedAmount); - } - -} +package io.oasp.gastronomy.restaurant.general.common; + +import io.oasp.gastronomy.restaurant.general.common.api.MoneyHelper; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.module.test.common.base.ModuleTest; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +/** + * This class tests the {@link MoneyHelper}. Especially summing a List of @Link {@link Money}s. + * + * @author mvielsac + */ +public class MoneyHelperTest extends ModuleTest { + + // /** + // * Test for summing up {@link Money}s with other currency (USD) then default (EUR). + // */ + // @Test + // public void sumTestUSDList() { + // + // List moneyList = new ArrayList<>(); + // + // double[] amounts = { 10.0, 15.2, 47.11, 42.0 }; + // double sum = 0.0; + // + // for (double amount : amounts) { + // moneyList.add(MoneyHelper.getMoney(amount, "USD")); + // sum += amount; + // } + // + // Money summedAmount = MoneyHelper.sumMoneys(moneyList); + // + // assertThat(MoneyHelper.getMoney(sum, "USD")).isEqualTo(summedAmount); + // + // } + + /** + * Test behavior when passing an empty list. + */ + @Test + public void sumTestEmptyList() { + + List moneyList = new ArrayList<>(); + Money summedAmount = MoneyHelper.sumMoneys(moneyList); + assertThat(MoneyHelper.ZERO_MONEY).isEqualTo(summedAmount); + } + + /** + * Test for summing up {@link Money}s with default currency (EUR). + */ + @Test + public void sumTestEURList() { + + List moneyList = new ArrayList<>(); + + double[] amounts = { 15.28, 11.47, 4.20 }; + double sum = 0.0; + + for (double amount : amounts) { + moneyList.add(MoneyHelper.getMoneyWithDefaultCurrency(amount)); + sum += amount; + } + + Money summedAmount = MoneyHelper.sumMoneys(moneyList); + + assertThat(MoneyHelper.getMoney(sum, "EUR")).isEqualTo(summedAmount); + } + +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java similarity index 71% rename from oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java rename to samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java index 4cb253b66..fe0978a25 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/PermissionCheckTest.java @@ -1,65 +1,69 @@ -package io.oasp.gastronomy.restaurant.general.common; - -import static org.junit.Assert.assertTrue; - -import java.lang.reflect.Method; -import java.util.Set; - -import javax.annotation.security.DenyAll; -import javax.annotation.security.PermitAll; -import javax.annotation.security.RolesAllowed; - -import net.sf.mmm.util.filter.api.Filter; -import net.sf.mmm.util.reflect.api.ReflectionUtil; -import net.sf.mmm.util.reflect.base.ReflectionUtilImpl; - -import org.junit.Test; - -/** - * Tests the permission check in logic layer. - * - * @author jmetzler - */ -public class PermissionCheckTest { - - /** - * Check if all relevant methods in use case implementations have permission checks i.e. {@link RolesAllowed}, - * {@link DenyAll} or {@link PermitAll} annotation is applied. This is only checked for methods that are declared in - * the corresponding interface and thus have the {@link Override} annotations applied. - */ - @Test - public void permissionCheckAnnotationPresent() { - - String packageName = "io.oasp.gastronomy.restaurant"; - Filter filter = new Filter() { - - @Override - public boolean accept(String value) { - - return value.contains(".logic.impl.usecase.Uc") && value.endsWith("Impl"); - } - - }; - ReflectionUtil ru = ReflectionUtilImpl.getInstance(); - Set classNames = ru.findClassNames(packageName, true, filter); - Set> classes = ru.loadClasses(classNames); - for (Class clazz : classes) { - Method[] methods = clazz.getDeclaredMethods(); - for (Method method : methods) { - Method parentMethod = ru.getParentMethod(method); - if (parentMethod != null) { - Class declaringClass = parentMethod.getDeclaringClass(); - if (declaringClass.isInterface() && declaringClass.getSimpleName().startsWith("Uc")) { - // ... - assertTrue( - - "Method " + method.getName() + " in Class " + clazz.getSimpleName() + " is missing access control", - method.getAnnotation(RolesAllowed.class) != null || method.getAnnotation(DenyAll.class) != null - || method.getAnnotation(PermitAll.class) != null); - } - } - } - } - } - -} +package io.oasp.gastronomy.restaurant.general.common; + +import io.oasp.module.test.common.base.ModuleTest; + +import java.lang.reflect.Method; +import java.util.Set; + +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + +import net.sf.mmm.util.filter.api.Filter; +import net.sf.mmm.util.reflect.api.ReflectionUtil; +import net.sf.mmm.util.reflect.base.ReflectionUtilImpl; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; + +/** + * Tests the permission check in logic layer. + * + * @author jmetzler + */ +public class PermissionCheckTest extends ModuleTest { + + /** + * Check if all relevant methods in use case implementations have permission checks i.e. {@link RolesAllowed}, + * {@link DenyAll} or {@link PermitAll} annotation is applied. This is only checked for methods that are declared in + * the corresponding interface and thus have the {@link Override} annotations applied. + */ + @Test + public void permissionCheckAnnotationPresent() { + + String packageName = "io.oasp.gastronomy.restaurant"; + Filter filter = new Filter() { + + @Override + public boolean accept(String value) { + + return value.contains(".logic.impl.usecase.Uc") && value.endsWith("Impl"); + } + + }; + ReflectionUtil ru = ReflectionUtilImpl.getInstance(); + Set classNames = ru.findClassNames(packageName, true, filter); + Set> classes = ru.loadClasses(classNames); + SoftAssertions assertions = new SoftAssertions(); + for (Class clazz : classes) { + Method[] methods = clazz.getDeclaredMethods(); + for (Method method : methods) { + Method parentMethod = ru.getParentMethod(method); + if (parentMethod != null) { + Class declaringClass = parentMethod.getDeclaringClass(); + if (declaringClass.isInterface() && declaringClass.getSimpleName().startsWith("Uc")) { + boolean hasAnnotation = false; + if (method.getAnnotation(RolesAllowed.class) != null || method.getAnnotation(DenyAll.class) != null + || method.getAnnotation(PermitAll.class) != null) { + hasAnnotation = true; + } + assertions.assertThat(hasAnnotation) + .as("Method " + method.getName() + " in Class " + clazz.getSimpleName() + " is missing access control") + .isTrue(); + } + } + } + } + assertions.assertAll(); + } +} diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/TestUtil.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/TestUtil.java new file mode 100644 index 000000000..1676899e6 --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/common/TestUtil.java @@ -0,0 +1,32 @@ +package io.oasp.gastronomy.restaurant.general.common; + +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * This is a utility for testing. It allows to simulate authentication for component testing. + * + * @author hohwille + */ +public class TestUtil { + + /** + * @param login the id of the user to run the test as. + * @param permissions the permissions for the test. + */ + public static void login(String login, String... permissions) { + + Authentication authentication = new TestingAuthenticationToken(login, login, permissions); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + /** + * Logs off any {@link #login(String, String...) previously logged on user}. + */ + public static void logout() { + + SecurityContextHolder.getContext().setAuthentication(null); + } + +} diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/configuration/BeansJpaConfiguration.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/configuration/BeansJpaConfiguration.java new file mode 100644 index 000000000..33e3bed64 --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/general/configuration/BeansJpaConfiguration.java @@ -0,0 +1,68 @@ +package io.oasp.gastronomy.restaurant.general.configuration; + +import io.oasp.gastronomy.restaurant.general.dataaccess.base.DatabaseMigrator; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Java configuration for JPA + * + * @author tkuzynow + */ +@Configuration +// @EnableTransactionManagement +public class BeansJpaConfiguration { + + private @Autowired EntityManagerFactory entityManagerFactory; + + private @Autowired DataSource appDataSource; + + @Value("${database.migration.auto}") + private Boolean enabled; + + @Value("${database.migration.testdata}") + private Boolean testdata; + + @Value("${database.migration.clean}") + private Boolean clean; + + @Bean + public DatabaseMigrator getFlyway() { + + DatabaseMigrator migrator = new DatabaseMigrator(); + migrator.setClean(this.clean); + migrator.setDataSource(this.appDataSource); + migrator.setEnabled(this.enabled); + migrator.setTestdata(this.testdata); + return migrator; + + } + + @PostConstruct + public void migrate() { + + getFlyway().migrate(); + } + + // @Bean + // public PersistenceExceptionTranslationPostProcessor getPersistenceExceptionTranslationPostProcessor() { + // + // return new PersistenceExceptionTranslationPostProcessor(); + // } + // + // @Bean + // public SharedEntityManagerBean getEntityManagerFactoryBean() { + // + // SharedEntityManagerBean bean = new SharedEntityManagerBean(); + // bean.setEntityManagerFactory(this.entityManagerFactory); + // return bean; + // } + // +} diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/ProductImportJobTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/ProductImportJobTest.java new file mode 100644 index 000000000..09040adff --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/offermanagement/batch/impl/productimport/ProductImportJobTest.java @@ -0,0 +1,91 @@ +package io.oasp.gastronomy.restaurant.offermanagement.batch.impl.productimport; + +import io.oasp.gastronomy.restaurant.SpringBootApp; +import io.oasp.gastronomy.restaurant.general.common.AbstractSpringBatchIntegrationTest; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.Offermanagement; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.DrinkEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.MealEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferEto; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.ProductEto; + +import java.util.List; + +import javax.inject.Inject; + +import org.junit.Test; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; + +/** + * End-To-End test job "import offer management from csv" + * + * @author jczas + */ +@SpringApplicationConfiguration(classes = { SpringBootApp.class }, locations = { "classpath:/config/app/batch/beans-productimport.xml" }) +@WebAppConfiguration +public class ProductImportJobTest extends AbstractSpringBatchIntegrationTest { + + @Inject + private Job productImportJob; + + @Inject + private Offermanagement offermanagement; + + /** + * @throws Exception thrown by JobLauncherTestUtils + */ + @Test + public void testJob() throws Exception { + + // login + login("chief", "chief", "FindOffer", "SaveOffer", "DeleteOffer", "FindProduct", "SaveProduct", "DeleteProduct"); + + cleanDatabase(); + + // configure job + JobParametersBuilder jobParameterBuilder = new JobParametersBuilder(); + jobParameterBuilder.addString("drinks.file", "classpath:ProductImportJobTest/data/drinks.csv"); + jobParameterBuilder.addString("meals.file", "classpath:ProductImportJobTest/data/meals.csv"); + JobParameters jobParameters = jobParameterBuilder.toJobParameters(); + + // run job + JobExecution jobExecution = getJobLauncherTestUtils(this.productImportJob).launchJob(jobParameters); + + // check results + // - job status + assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); + + // - imported data (there is 7 products in setup data) + List allProducts = this.offermanagement.findAllProducts(); + assertThat(allProducts).hasSize(7); + + // - exemplary drink + DrinkEto drink = (DrinkEto) allProducts.get(0); + assertThat(drink.getName()).isEqualTo("Heineken"); + assertThat(drink.getDescription()).isEqualTo("Pretty good beer"); + assertThat(drink.getPictureId()).isEqualTo(1); + assertThat(drink.isAlcoholic()).isTrue(); + + // - exemplary meal + MealEto meal = (MealEto) allProducts.get(3); + assertThat(meal.getName()).isEqualTo("Bratwurst"); + assertThat(meal.getDescription()).isEqualTo("Tasty sausage"); + assertThat(meal.getPictureId()).isEqualTo(1); + } + + private void cleanDatabase() { + + for (OfferEto offer : this.offermanagement.findAllOffers()) { + this.offermanagement.deleteOffer(offer.getId()); + } + + for (ProductEto product : this.offermanagement.findAllProducts()) { + this.offermanagement.deleteProduct(product.getId()); + } + } +} diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/BillExportJobTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/BillExportJobTest.java new file mode 100644 index 000000000..a90bc1e5d --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/batch/impl/billexport/BillExportJobTest.java @@ -0,0 +1,100 @@ +package io.oasp.gastronomy.restaurant.salesmanagement.batch.impl.billexport; + +import io.oasp.gastronomy.restaurant.SpringBootApp; +import io.oasp.gastronomy.restaurant.general.common.AbstractSpringBatchIntegrationTest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import javax.inject.Inject; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.test.AssertFile; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.test.context.web.WebAppConfiguration; + +/** + * End-To-End test job "import offer management from csv" + * + * @author jczas + */ +@SpringApplicationConfiguration(classes = { SpringBootApp.class }, locations = { "classpath:/config/app/batch/beans-billexport.xml" }) +@WebAppConfiguration +public class BillExportJobTest extends AbstractSpringBatchIntegrationTest { + private static final Logger LOG = LoggerFactory.getLogger(AbstractSpringBatchIntegrationTest.class); + + @Inject + private Job billExportJob; + + /** + * @throws Exception thrown by JobLauncherTestUtils + */ + @Test + public void testJob() throws Exception { + + // login + login("chief", "chief", "FindOffer", "SaveOffer", "DeleteOffer", "FindProduct", "SaveProduct", "DeleteProduct"); + + // setup test data + this.flyway.importTestData("classpath:BillExportJobTest/setup/db"); + + File targetFile = new File("./tmp/bills.csv"); + File expectedFile = new ClassPathResource("BillExportJobTest/expected/bills.csv").getFile(); + + // configure job + JobParametersBuilder jobParameterBuilder = new JobParametersBuilder(); + jobParameterBuilder.addString("bills.file", targetFile.getPath()); + JobParameters jobParameters = jobParameterBuilder.toJobParameters(); + + // run job + JobExecution jobExecution = getJobLauncherTestUtils(this.billExportJob).launchJob(jobParameters); + + // check results + // - job status + assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); + + // - exported data + assertThat(targetFile.exists()).isTrue(); + assertThat(expectedFile.exists()).isTrue(); + + logFileContent(expectedFile); + logFileContent(targetFile); + + AssertFile.assertFileEquals(expectedFile, targetFile); + } + + private void logFileContent(File file) { + + try { + LOG.debug("--> file content: " + file.getPath()); + BufferedReader br = null; + + String line; + try { + br = new BufferedReader(new FileReader(file)); + + while ((line = br.readLine()) != null) { + LOG.debug(line); + } + } finally { + if (br != null) { + br.close(); + } + } + LOG.debug("<-- file content: " + file.getPath()); + } catch (IOException e) { + LOG.debug(e.toString()); + e.printStackTrace(); + } + } +} diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java similarity index 51% rename from oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java rename to samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java index 0ab210896..76461d950 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/BillDaoTest.java @@ -1,10 +1,10 @@ package io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.impl.dao; -import io.oasp.gastronomy.restaurant.general.common.AbstractSpringIntegrationTest; +import io.oasp.gastronomy.restaurant.SpringBootApp; import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.BillEntity; import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.dao.BillDao; -import io.oasp.module.configuration.common.api.ApplicationConfigurationConstants; +import io.oasp.module.test.common.base.ComponentTest; import java.util.List; @@ -14,23 +14,19 @@ import javax.persistence.TypedQuery; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import org.springframework.test.context.transaction.TransactionalTestExecutionListener; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.transaction.annotation.Transactional; /** + * Test of {@link BillDao}. * * @author mvielsac */ -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class }) -@ContextConfiguration({ ApplicationConfigurationConstants.BEANS_DATA_ACCESS }) @Transactional -public class BillDaoTest extends AbstractSpringIntegrationTest { +@SpringApplicationConfiguration(classes = { SpringBootApp.class }) +@WebAppConfiguration +public class BillDaoTest extends ComponentTest { @Inject private BillDao billDao; @@ -49,20 +45,20 @@ public void testPersist() { bill.setTotal(new Money(42.42)); bill.setTip(new Money(1.0)); bill.setPayed(true); - assertNull(bill.getId()); + assertThat(bill.getId()).isNull(); this.billDao.save(bill); - assertNotNull(bill.getId()); + assertThat(bill.getId()).isNotNull(); BillEntity loadedBill = this.billDao.findOne(bill.getId()); - assertEquals(bill, loadedBill); + assertThat(bill).isEqualTo(loadedBill); TypedQuery query = - this.entityManager.createQuery("SELECT b from Bill b where b.total > 43", BillEntity.class); + this.entityManager.createQuery("SELECT b from BillEntity b where b.total > 43", BillEntity.class); List resultList = query.getResultList(); - assertTrue(resultList.isEmpty()); + assertThat(resultList.isEmpty()).isTrue(); - query = this.entityManager.createQuery("SELECT b from Bill b where b.total < 43", BillEntity.class); + query = this.entityManager.createQuery("SELECT b from BillEntity b where b.total < 43", BillEntity.class); resultList = query.getResultList(); - assertTrue(!resultList.isEmpty()); + assertThat(!resultList.isEmpty()).isTrue(); } diff --git a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java similarity index 72% rename from oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java rename to samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java index 6ff3fe43c..718193527 100644 --- a/oasp4j-samples/oasp4j-sample-core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/dataaccess/impl/dao/DrinkDaoTest.java @@ -1,128 +1,125 @@ -package io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.impl.dao; - -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity; -import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; -import io.oasp.module.configuration.common.api.ApplicationConfigurationConstants; -import io.oasp.module.jpa.dataaccess.api.RevisionMetadata; - -import java.util.List; - -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.transaction.Transactional; - -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; - -/** - * Test class to test the {@link DrinkDao}. - * - * @author jmetzler - */ -@RunWith(SpringJUnit4ClassRunner.class) -@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class }) -@ContextConfiguration({ ApplicationConfigurationConstants.BEANS_DATA_ACCESS, -"classpath:/config/app/service/beans-test-service-rest.xml" }) -@ActiveProfiles("db-plain") -public class DrinkDaoTest extends Assert { - - @Inject - DrinkDaoTestBean testBean; - - /** - * Test to check if the DrinkEntity is audited. All steps are executed in separate transactions in order to actually - * write to the database. Otherwise hibernate envers won't work. - */ - @Test - public void checkAudit() { - - DrinkEntity drink = this.testBean.create(); - long drinkId = drink.getId(); - this.testBean.update(drinkId); - this.testBean.verify(drinkId); - - } - - /** - * - * This type provides methods in a transactional environment for the containing test class. All methods, annotated - * with the {@link Transactional} annotation, are executed in separate transaction, thus one test case can execute - * multiple transactions. - * - * @author jmetzler - */ - static class DrinkDaoTestBean { - - private final String description = "some description"; - - private final String changedDescription = "some changed description"; - - @Inject - private DrinkDao drinkDao; - - @PersistenceContext - private EntityManager entityManager; - - @Transactional - public DrinkEntity create() { - - DrinkEntity drink = new DrinkEntity(); - drink.setAlcoholic(false); - drink.setDescription(this.description); - drink.setName("some name"); - assertNull(drink.getId()); - drink = this.drinkDao.save(drink); - return drink; - } - - @Transactional - public void update(long id) { - - DrinkEntity drink = this.drinkDao.find(id); - drink.setAlcoholic(true); - drink.setDescription(this.changedDescription); - this.drinkDao.save(drink); - } - - @Transactional - public void verify(long id) { - - AuditReader auditReader = AuditReaderFactory.get(this.entityManager); - - assertTrue(auditReader.isEntityClassAudited(DrinkEntity.class)); - - List revisions = auditReader.getRevisions(DrinkEntity.class, id); - assertEquals(2, revisions.size()); - - List history = this.drinkDao.getRevisionHistoryMetadata(id); - assertEquals(2, history.size()); - - // get first revision - Number rev = history.get(0).getRevision(); - DrinkEntity drink = this.drinkDao.load(id, rev); - assertTrue(drink.getDescription().equals(this.description)); - - // get second revision - rev = history.get(1).getRevision(); - drink = this.drinkDao.load(id, rev); - assertTrue(drink.getDescription().equals(this.changedDescription)); - } - - /** - * @param entityManager the entityManager to set - */ - public void setEntityManager(EntityManager entityManager) { - - this.entityManager = entityManager; - } - }; -} +package io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.impl.dao; + +import io.oasp.gastronomy.restaurant.SpringBootApp; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.DrinkDao; +import io.oasp.module.jpa.dataaccess.api.RevisionMetadata; +import io.oasp.module.test.common.base.ComponentTest; + +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.transaction.Transactional; + +import org.hibernate.envers.AuditReader; +import org.hibernate.envers.AuditReaderFactory; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; + +/** + * Test class to test the {@link DrinkDao}. + * + * @author jmetzler + */ + +@SpringApplicationConfiguration(classes = { SpringBootApp.class }) +@WebAppConfiguration +public class DrinkDaoTest extends ComponentTest { + + @Inject + DrinkDaoTestBean testBean; + + /** + * Test to check if the DrinkEntity is audited. All steps are executed in separate transactions in order to actually + * write to the database. Otherwise hibernate envers won't work. + */ + @Test + public void checkAudit() { + + DrinkEntity drink = this.testBean.create(); + long drinkId = drink.getId(); + this.testBean.update(drinkId); + this.testBean.verify(drinkId); + + } + + /** + * + * This type provides methods in a transactional environment for the containing test class. All methods, annotated + * with the {@link Transactional} annotation, are executed in separate transaction, thus one test case can execute + * multiple transactions. + * + * @author jmetzler + */ + @Named + static class DrinkDaoTestBean { + + private final String description = "some description"; + + private final String changedDescription = "some changed description"; + + @Inject + private DrinkDao drinkDao; + + @PersistenceContext + private EntityManager entityManager; + + @Transactional + public DrinkEntity create() { + + DrinkEntity drink = new DrinkEntity(); + drink.setAlcoholic(false); + drink.setDescription(this.description); + drink.setName("some name"); + assertThat(drink.getId()).isNull(); + drink = this.drinkDao.save(drink); + return drink; + } + + @Transactional + public void update(long id) { + + DrinkEntity drink = this.drinkDao.find(id); + drink.setAlcoholic(true); + drink.setDescription(this.changedDescription); + this.drinkDao.save(drink); + } + + @Transactional + public void verify(long id) { + + AuditReader auditReader = AuditReaderFactory.get(this.entityManager); + + assertThat(auditReader.isEntityClassAudited(DrinkEntity.class)).isTrue(); + + List revisions = auditReader.getRevisions(DrinkEntity.class, id); + assertThat(2).isEqualTo(revisions.size()); + + List history = this.drinkDao.getRevisionHistoryMetadata(id); + assertThat(2).isEqualTo(history.size()); + + // get first revision + Number rev = history.get(0).getRevision(); + DrinkEntity drink = this.drinkDao.load(id, rev); + assertThat(drink.getDescription()).isEqualTo(this.description); + + // get second revision + rev = history.get(1).getRevision(); + drink = this.drinkDao.load(id, rev); + assertThat(drink.getDescription()).isEqualTo(this.changedDescription); + } + + /** + * @param entityManager the entityManager to set + */ + public void setEntityManager(EntityManager entityManager) { + + this.entityManager = entityManager; + } + }; +} diff --git a/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java new file mode 100644 index 000000000..020471d80 --- /dev/null +++ b/samples/core/src/test/java/io/oasp/gastronomy/restaurant/salesmanagement/logic/impl/SalesManagementTest.java @@ -0,0 +1,99 @@ +package io.oasp.gastronomy.restaurant.salesmanagement.logic.impl; + +import javax.inject.Inject; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.web.WebAppConfiguration; + +import io.oasp.gastronomy.restaurant.SpringBootApp; +import io.oasp.gastronomy.restaurant.general.common.TestUtil; +import io.oasp.gastronomy.restaurant.general.common.api.constants.PermissionConstants; +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.OrderPositionState; +import io.oasp.gastronomy.restaurant.salesmanagement.common.api.datatype.ProductOrderState; +import io.oasp.gastronomy.restaurant.salesmanagement.dataaccess.api.dao.OrderPositionDao; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.Salesmanagement; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderEto; +import io.oasp.gastronomy.restaurant.salesmanagement.logic.api.to.OrderPositionEto; +import io.oasp.module.test.common.base.ComponentTest; + +/** + * This is the test-case of {@link Salesmanagement}. + * + * @author hohwille + */ +@SpringApplicationConfiguration(classes = { SpringBootApp.class }) +@WebAppConfiguration +public class SalesManagementTest extends ComponentTest { + @Inject + private Salesmanagement salesManagement; + + @Inject + private OrderPositionDao orderPositionDao; + + @Before + public void setUp() { + + TestUtil.login("waiter", PermissionConstants.FIND_ORDER_POSITION, PermissionConstants.SAVE_ORDER_POSITION, + PermissionConstants.SAVE_ORDER, PermissionConstants.FIND_OFFER); + } + + @After + public void tearDown() { + + TestUtil.logout(); + } + + /** + * Tests if the {@link OrderPositionState} is persisted correctly. The test modifies the {@link OrderPositionState} as + * well as the drinkState {@link ProductOrderState}. The test focuses on saving {@link OrderPositionEto} saving and + * verification of state change. + */ + @Test + public void testOrderPositionStateChange() { + + try { + OrderEto order = new OrderEto(); + order.setTableId(1L); + order = this.salesManagement.saveOrder(order); + OrderPositionEto orderPosition = new OrderPositionEto(); + orderPosition.setOfferId(5L); + orderPosition.setOrderId(order.getId()); + orderPosition.setOfferName("Cola"); + orderPosition.setPrice(new Money(1.2)); + + orderPosition = this.salesManagement.saveOrderPosition(orderPosition); + + orderPosition.setState(OrderPositionState.ORDERED); + orderPosition.setDrinkState(ProductOrderState.ORDERED); + + OrderPositionEto updatedOrderPosition = this.salesManagement.saveOrderPosition(orderPosition); + assertThat(updatedOrderPosition.getState()).isEqualTo(OrderPositionState.ORDERED); + + updatedOrderPosition.setState(OrderPositionState.PREPARED); + updatedOrderPosition.setDrinkState(ProductOrderState.PREPARED); + + updatedOrderPosition = this.salesManagement.saveOrderPosition(updatedOrderPosition); + + assertThat(updatedOrderPosition.getState()).isEqualTo(OrderPositionState.PREPARED); + } catch (ConstraintViolationException e) { + // BV is really painful as you need such code to see the actual error in JUnit. + StringBuilder sb = new StringBuilder(64); + sb.append("Constraints violated:"); + for (ConstraintViolation v : e.getConstraintViolations()) { + sb.append("\n"); + sb.append(v.getPropertyPath()); + sb.append(":"); + sb.append(v.getMessage()); + } + throw new IllegalStateException(sb.toString(), e); + } + + } + +} diff --git a/samples/core/src/test/resources/AllTests/setup/db/V9001_1__Delete_data.sql b/samples/core/src/test/resources/AllTests/setup/db/V9001_1__Delete_data.sql new file mode 100644 index 000000000..a8864cc9c --- /dev/null +++ b/samples/core/src/test/resources/AllTests/setup/db/V9001_1__Delete_data.sql @@ -0,0 +1,13 @@ +SET FOREIGN_KEY_CHECKS=0; + +DELETE FROM RESTAURANTTABLE; +DELETE FROM RESTAURANTORDER; +DELETE FROM PRODUCT; +DELETE FROM OFFER; +DELETE FROM ORDERPOSITION; +DELETE FROM BILL; + +--Keep Staffmembers to allow authentication +--DELETE FROM STAFFMEMBER; + +SET FOREIGN_KEY_CHECKS=1; diff --git a/samples/core/src/test/resources/BillExportJobTest/expected/bills.csv b/samples/core/src/test/resources/BillExportJobTest/expected/bills.csv new file mode 100644 index 000000000..81d4e4dce --- /dev/null +++ b/samples/core/src/test/resources/BillExportJobTest/expected/bills.csv @@ -0,0 +1,10 @@ +1,true,14.98 EUR,1.30 EUR,1,1,,1,Schnitzel-Menü,DELIVERED,6.99 EUR,mit Ketschup +1,true,14.98 EUR,1.30 EUR,2,1,,2,Goulasch-Menü,DELIVERED,7.99 EUR, +1,true,14.98 EUR,1.30 EUR,1,1,,1,Schnitzel-Menü,DELIVERED,6.99 EUR,mit Ketschup +1,true,14.98 EUR,1.30 EUR,2,1,,2,Goulasch-Menü,DELIVERED,7.99 EUR, +2,true,14.98 EUR,1.40 EUR,3,1,,3,Pfifferlinge-Menü,DELIVERED,8.99 EUR, +2,true,14.98 EUR,1.40 EUR,4,1,,4,Salat-Menü,DELIVERED,5.99 EUR, +2,true,14.98 EUR,1.40 EUR,3,1,,3,Pfifferlinge-Menü,DELIVERED,8.99 EUR, +2,true,14.98 EUR,1.40 EUR,4,1,,4,Salat-Menü,DELIVERED,5.99 EUR, +2,true,14.98 EUR,1.40 EUR,3,1,,3,Pfifferlinge-Menü,DELIVERED,8.99 EUR, +2,true,14.98 EUR,1.40 EUR,4,1,,4,Salat-Menü,DELIVERED,5.99 EUR, diff --git a/samples/core/src/test/resources/BillExportJobTest/setup/db/V9901_1__Import_data.sql b/samples/core/src/test/resources/BillExportJobTest/setup/db/V9901_1__Import_data.sql new file mode 100644 index 000000000..5f29a6b91 --- /dev/null +++ b/samples/core/src/test/resources/BillExportJobTest/setup/db/V9901_1__Import_data.sql @@ -0,0 +1,46 @@ +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (101, 1, 1, 2); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (102, 1, 2, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (103, 1, 3, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (104, 1, 4, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (105, 1, 5, 0); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (1, 1, 'Meal', 'Schnitzel'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (2, 1, 'Meal', 'Goulasch'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (3, 1, 'Meal', 'Pfifferlinge'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (4, 1, 'Meal', 'Salat'); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (5, 1, 'SideDish', 'Pommes'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (6, 1, 'SideDish', 'Reis'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (7, 1, 'SideDish', 'Brot'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (8, 1, 'SideDish', 'Knödel'); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (9, 1, 'Drink', 'Wasser', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (10, 1, 'Drink', 'Cola', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (11, 1, 'Drink', 'Bier', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (12, 1, 'Drink', 'Wein / Apfelwein', false); + +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (1, 1, 'Schnitzel-Menü', 'Description of Schnitzel-Menü', 0, 1, 5, 10, 6.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (2, 1, 'Goulasch-Menü', 'Description of Goulasch-Menü', 0, 2, 6, 11, 7.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (3, 1, 'Pfifferlinge-Menü', 'Description of Pfifferlinge-Menü', 0, 3, 8, 12, 8.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (4, 1, 'Salat-Menü', 'Description of Salat-Menü', 0, 4, 7, 9, 5.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (5, 1, 'Cola', 'Description of Salat-Menü', 0, null, null, 10, 1.20); + +INSERT INTO RESTAURANTORDER (id, modificationCounter, table_id, state) VALUES (1, 1, 101, 1); + +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (1, 1, 1, 'Schnitzel-Menü', 'mit Ketschup', 2, 2, 1, 6.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (2, 1, 2, 'Goulasch-Menü', '', 2, 2, 1, 7.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (3, 1, 3, 'Pfifferlinge-Menü','', 2, 2, 1, 8.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (4, 1, 4, 'Salat-Menü', '', 2, 2, 1, 5.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (5, 1, 5, 'Cola', '', 2, 2, 1, 5.99); + +INSERT INTO BILL (id, modificationCounter, payed, total, tip) VALUES (1, 1, true, 14.98, 1.3); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,1); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,2); + +INSERT INTO BILL (id, modificationCounter, payed, total,tip) VALUES (2, 1, true, 14.98, 1.4); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,3); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,4); + +INSERT INTO BILL (id, modificationCounter, payed, total,tip) VALUES (3, 1, true, 15.98, 1.5); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,3); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,4); \ No newline at end of file diff --git a/samples/core/src/test/resources/ProductImportJobTest/data/drinks.csv b/samples/core/src/test/resources/ProductImportJobTest/data/drinks.csv new file mode 100644 index 000000000..5870f32c7 --- /dev/null +++ b/samples/core/src/test/resources/ProductImportJobTest/data/drinks.csv @@ -0,0 +1,3 @@ +Heineken, Pretty good beer, 1, true +Dilmah, Very tasty black tea, 2, false +Pepsi, Nice drink, 3, false diff --git a/samples/core/src/test/resources/ProductImportJobTest/data/meals.csv b/samples/core/src/test/resources/ProductImportJobTest/data/meals.csv new file mode 100644 index 000000000..914d8717a --- /dev/null +++ b/samples/core/src/test/resources/ProductImportJobTest/data/meals.csv @@ -0,0 +1,4 @@ +Bratwurst, Tasty sausage, 1 +Hamburger, Big bun with meat, 2 +Tofu, Food made from soy milk, 3 +Pierogi, Very good filled dumplings, 4 diff --git a/samples/core/src/test/resources/config/application.properties b/samples/core/src/test/resources/config/application.properties new file mode 100644 index 000000000..ac58656d2 --- /dev/null +++ b/samples/core/src/test/resources/config/application.properties @@ -0,0 +1,11 @@ +# https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-user-a-random-unassigned-http-port +server.port=0 + +# Flyway for Database Setup and Migrations +flyway.enabled=true +flyway.clean-on-validation-error=true + +# Flyway for setting up testdata in database +database.migration.auto=true +database.migration.testdata=false +database.migration.clean=false diff --git a/oasp4j-samples/pom.xml b/samples/pom.xml similarity index 86% rename from oasp4j-samples/pom.xml rename to samples/pom.xml index 4210fba8f..ed9fe7e0e 100644 --- a/oasp4j-samples/pom.xml +++ b/samples/pom.xml @@ -21,8 +21,9 @@ - oasp4j-sample-core - oasp4j-sample-server + core + server + batch @@ -70,14 +71,6 @@ - - integration-test - - oasp4j-sample-core - oasp4j-sample-server - oasp4j-sample-server-integration - - subsystemtest @@ -87,9 +80,9 @@ systemtest - + - + \ No newline at end of file diff --git a/samples/server/pom.xml b/samples/server/pom.xml new file mode 100644 index 000000000..00b821882 --- /dev/null +++ b/samples/server/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + + io.oasp.java.dev + oasp4j-samples + dev-SNAPSHOT + + io.oasp.java.samples + oasp4j-sample-server + war + ${project.artifactId} + Server for the restaurant application - a simple example using the Open Application Standard Platform for Java (OASP4J). + + + 1.7 + + + + + ${project.groupId} + oasp4j-sample-core + ${project.version} + + + + + + jsclient + + + false + + + + + org.codehaus.mojo + exec-maven-plugin + + + npm-install + generate-sources + + exec + + + npm + + install + + ${js.client.dir} + + + + tsd-install + generate-sources + + exec + + + tsd + + install + + ${js.client.dir} + + + + gulp-clean + generate-sources + + exec + + + gulp + + clean + + ${js.client.dir} + + + + gulp-build + generate-sources + + exec + + + gulp + + build:dist + + ${js.client.dir} + + + + gulp-test + test + + exec + + + gulp + + test + + ${js.client.dir} + + + + + + + + + + + + + ${project.basedir}/src/main/resources + + + ${js.client.dir}/dist + static + + + + + org.springframework.boot + spring-boot-maven-plugin + + io.oasp.gastronomy.restaurant.SpringBootApp + bootified + ${project.artifactId} + WAR + + + + + + diff --git a/samples/server/src/main/resources/logback.xml b/samples/server/src/main/resources/logback.xml new file mode 100644 index 000000000..31c73687f --- /dev/null +++ b/samples/server/src/main/resources/logback.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oasp4j-samples/oasp4j-sample-server/src/main/webapp/META-INF/context.xml b/samples/server/src/main/webapp/META-INF/context.xml similarity index 100% rename from oasp4j-samples/oasp4j-sample-server/src/main/webapp/META-INF/context.xml rename to samples/server/src/main/webapp/META-INF/context.xml diff --git a/oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/gui/login.jsp b/samples/server/src/main/webapp/WEB-INF/gui/login.jsp similarity index 100% rename from oasp4j-samples/oasp4j-sample-server/src/main/webapp/WEB-INF/gui/login.jsp rename to samples/server/src/main/webapp/WEB-INF/gui/login.jsp diff --git a/samples/server/src/main/webapp/WEB-INF/web.xml b/samples/server/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..ff13aa773 --- /dev/null +++ b/samples/server/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/oasp4j-samples/oasp4j-sample-server/src/main/webapp/index.jsp b/samples/server/src/main/webapp/index.jsp similarity index 100% rename from oasp4j-samples/oasp4j-sample-server/src/main/webapp/index.jsp rename to samples/server/src/main/webapp/index.jsp diff --git a/src/main/javadoc/stylesheet.css b/src/main/javadoc/stylesheet.css deleted file mode 100644 index 546edf93f..000000000 --- a/src/main/javadoc/stylesheet.css +++ /dev/null @@ -1,478 +0,0 @@ -/* Javadoc style sheet */ -/* -Overall document style -*/ -body { - background-color:#ffffff; - color:#353833; - font-family:Arial, Helvetica, sans-serif; - font-size:76%; - margin:0; -} -a:link, a:visited { - text-decoration:none; - color:#4c6b87; -} -a:hover, a:focus { - text-decoration:none; - color:#bb7a2a; -} -a:active { - text-decoration:none; - color:#4c6b87; -} -a[name] { - color:#353833; -} -a[name]:hover { - text-decoration:none; - color:#353833; -} -pre { - font-size:1.3em; - white-space: pre-wrap; - background: #F6F6F6; - border-left: 5px solid #6CE26C; - padding: 0.5em; -} -h1 { - font-size:1.8em; -} -h2 { - font-size:1.5em; -} -h3 { - font-size:1.4em; -} -h4 { - font-size:1.3em; -} -h5 { - font-size:1.2em; -} -h6 { - font-size:1.1em; -} -ul { - list-style-type:disc; -} -code, tt { - font-size:1.2em; -} -dt code { - font-size:1.2em; -} -table tr td dt code { - font-size:1.2em; - vertical-align:top; -} -sup { - font-size:.6em; -} -/* -Document title and Copyright styles -*/ -.clear { - clear:both; - height:0px; - overflow:hidden; -} -.aboutLanguage { - float:right; - padding:0px 21px; - font-size:.8em; - z-index:200; - margin-top:-7px; -} -.legalCopy { - margin-left:.5em; -} -.bar a, .bar a:link, .bar a:visited, .bar a:active { - color:#FFFFFF; - text-decoration:none; -} -.bar a:hover, .bar a:focus { - color:#bb7a2a; -} -.tab { - background-color:#0066FF; - background-image:url(resources/titlebar.gif); - background-position:left top; - background-repeat:no-repeat; - color:#ffffff; - padding:8px; - width:5em; - font-weight:bold; -} -/* -Navigation bar styles -*/ -.bar { - background-image:url(resources/background.gif); - background-repeat:repeat-x; - color:#FFFFFF; - padding:.8em .5em .4em .8em; - height:auto;/*height:1.8em;*/ - font-size:1em; - margin:0; -} -.topNav { - background-image:url(resources/background.gif); - background-repeat:repeat-x; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - height:2.8em; - padding-top:10px; - overflow:hidden; -} -.bottomNav { - margin-top:10px; - background-image:url(resources/background.gif); - background-repeat:repeat-x; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - height:2.8em; - padding-top:10px; - overflow:hidden; -} -.subNav { - background-color:#dee3e9; - border-bottom:1px solid #9eadc0; - float:left; - width:100%; - overflow:hidden; -} -.subNav div { - clear:left; - float:left; - padding:0 0 5px 6px; -} -ul.navList, ul.subNavList { - float:left; - margin:0 25px 0 0; - padding:0; -} -ul.navList li{ - list-style:none; - float:left; - padding:3px 6px; -} -ul.subNavList li{ - list-style:none; - float:left; - font-size:90%; -} -.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { - color:#FFFFFF; - text-decoration:none; -} -.topNav a:hover, .bottomNav a:hover { - text-decoration:none; - color:#bb7a2a; -} -.navBarCell1Rev { - background-image:url(resources/tab.gif); - background-color:#a88834; - color:#FFFFFF; - margin: auto 5px; - border:1px solid #c9aa44; -} -/* -Page header and footer styles -*/ -.header, .footer { - clear:both; - margin:0 20px; - padding:5px 0 0 0; -} -.indexHeader { - margin:10px; - position:relative; -} -.indexHeader h1 { - font-size:1.3em; -} -.title { - color:#2c4557; - margin:10px 0; -} -.subTitle { - margin:5px 0 0 0; -} -.header ul { - margin:0 0 25px 0; - padding:0; -} -.footer ul { - margin:20px 0 5px 0; -} -.header ul li, .footer ul li { - list-style:none; - font-size:1.2em; -} -/* -Heading styles -*/ -div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { - background-color:#dee3e9; - border-top:1px solid #9eadc0; - border-bottom:1px solid #9eadc0; - margin:0 0 6px -8px; - padding:2px 5px; -} -ul.blockList ul.blockList ul.blockList li.blockList h3 { - background-color:#dee3e9; - border-top:1px solid #9eadc0; - border-bottom:1px solid #9eadc0; - margin:0 0 6px -8px; - padding:2px 5px; -} -ul.blockList ul.blockList li.blockList h3 { - padding:0; - margin:15px 0; -} -ul.blockList li.blockList h2 { - padding:0px 0 20px 0; -} -/* -Page layout container styles -*/ -.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { - clear:both; - padding:10px 20px; - position:relative; -} -.indexContainer { - margin:10px; - position:relative; - font-size:1.0em; -} -.indexContainer h2 { - font-size:1.1em; - padding:0 0 3px 0; -} -.indexContainer ul { - margin:0; - padding:0; -} -.indexContainer ul li { - list-style:none; -} -.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { - font-size:1.1em; - font-weight:bold; - margin:10px 0 0 0; - color:#4E4E4E; -} -.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { - margin:10px 0 10px 20px; -} -.serializedFormContainer dl.nameValue dt { - margin-left:1px; - font-size:1.1em; - display:inline; - font-weight:bold; -} -.serializedFormContainer dl.nameValue dd { - margin:0 0 0 1px; - font-size:1.1em; - display:inline; -} -/* -List styles -*/ -ul.horizontal li { - display:inline; - font-size:0.9em; -} -ul.inheritance { - margin:0; - padding:0; -} -ul.inheritance li { - display:inline; - list-style:none; -} -ul.inheritance li ul.inheritance { - margin-left:15px; - padding-left:15px; - padding-top:1px; -} -ul.blockList, ul.blockListLast { - margin:10px 0 10px 0; - padding:0; -} -ul.blockList li.blockList, ul.blockListLast li.blockList { - list-style:none; - margin-bottom:25px; -} -ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { - padding:0px 20px 5px 10px; - border:1px solid #9eadc0; - background-color:#f9f9f9; -} -ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { - padding:0 0 5px 8px; - background-color:#ffffff; - border:1px solid #9eadc0; - border-top:none; -} -ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { - margin-left:0; - padding-left:0; - padding-bottom:15px; - border:none; - border-bottom:1px solid #9eadc0; -} -ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { - list-style:none; - border-bottom:none; - padding-bottom:0; -} -table tr td dl, table tr td dl dt, table tr td dl dd { - margin-top:0; - margin-bottom:1px; -} -/* -Table styles -*/ -.contentContainer table, .classUseContainer table, .constantValuesContainer table { - border-bottom:1px solid #9eadc0; - width:100%; -} -.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table { - width:100%; -} -.contentContainer .description table, .contentContainer .details table { - border-bottom:none; -} -.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{ - vertical-align:top; - padding-right:20px; -} -.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast, -.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast, -.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne, -.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne { - padding-right:3px; -} -.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption { - position:relative; - text-align:left; - background-repeat:no-repeat; - color:#FFFFFF; - font-weight:bold; - clear:none; - overflow:hidden; - padding:0px; - margin:0px; -} -caption a:link, caption a:hover, caption a:active, caption a:visited { - color:#FFFFFF; -} -.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span { - white-space:nowrap; - padding-top:8px; - padding-left:8px; - display:block; - float:left; - background-image:url(resources/titlebar.gif); - height:18px; -} -.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd { - width:10px; - background-image:url(resources/titlebar_end.gif); - background-repeat:no-repeat; - background-position:top right; - position:relative; - float:left; -} -ul.blockList ul.blockList li.blockList table { - margin:0 0 12px 0px; - width:100%; -} -.tableSubHeadingColor { - background-color: #EEEEFF; -} -.altColor { - background-color:#eeeeef; -} -.rowColor { - background-color:#ffffff; -} -.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td { - text-align:left; - padding:3px 3px 3px 7px; -} -th.colFirst, th.colLast, th.colOne, .constantValuesContainer th { - background:#dee3e9; - border-top:1px solid #9eadc0; - border-bottom:1px solid #9eadc0; - text-align:left; - padding:3px 3px 3px 7px; -} -td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { - font-weight:bold; -} -td.colFirst, th.colFirst { - border-left:1px solid #9eadc0; - white-space:nowrap; -} -td.colLast, th.colLast { - border-right:1px solid #9eadc0; -} -td.colOne, th.colOne { - border-right:1px solid #9eadc0; - border-left:1px solid #9eadc0; -} -table.overviewSummary { - padding:0px; - margin-left:0px; -} -table.overviewSummary td.colFirst, table.overviewSummary th.colFirst, -table.overviewSummary td.colOne, table.overviewSummary th.colOne { - width:25%; - vertical-align:middle; -} -table.packageSummary td.colFirst, table.overviewSummary th.colFirst { - width:25%; - vertical-align:middle; -} -/* -Content styles -*/ -.description pre { - margin-top:0; -} -.deprecatedContent { - margin:0; - padding:10px 0; -} -.docSummary { - padding:0; -} -/* -Formatting effect styles -*/ -.sourceLineNo { - color:green; - padding:0 30px 0 0; -} -h1.hidden { - visibility:hidden; - overflow:hidden; - font-size:.9em; -} -.block { - display:block; - margin:3px 0 0 0; -} -.strong { - font-weight:bold; -} diff --git a/src/site/resources/favicon.ico b/src/site/resources/favicon.ico deleted file mode 100644 index d34b8be3d4c3521b3fd0655adeb6f5336699c988..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmbW1ZA_C_6vr;fp$cHUk+}vaVjpB5U(Sg`a zfuRhC-9QW2&bHxAicVWwD=+FO3bit9W!Au;p_GZERD5AVE%4i=h5CK>$$dHhbNes1I3Uvi9(OC2%T4~ec zG%vW%3Dx@)eI(?*3H-V%4nvl}`2ExLx~xCoN zsQgm;^^M@1CY5`EK3q+?Tx-+NQ2ciEEFGs~_I>t3+!ue2$yY6VP-h5gz80L-We}Wz z_Nq6y*-=HODUXUT1g44)@c%tZV8qKM!zxDot{6WY`WLrt7r$4%j9v2@?S|Fdux=z2 z3NaIYh|98trqX9=J(_}}ejR}UOO!i1Bhx<lHK`3%E6MJAyyBcZWaS zSBaLxG!yp&vQC_Y=aM_$Jb&0w$Q&uw3HGd)dHO_9xqCUm@dp^oHj$m0i1TuDM7AB< z%)vB4pU1gCM_0HO<%fb3>NL)3KIWJriAq@mjutKIoR#Fu+?1p*qHOzK^m=zDen}B<_xnMX-VHdh|O4&L$PQeQ)vOX9BI_d5p!$7-WuW6#`egKE|*6;dRv6 z%NV;m8No(<4ve{SkCswu_rJrTO@hvIWrQD1V)^L>8l~>~WkZZ_E?diCS+8g0*{(Zn zv>i{!v|FCB>o})W?@_Tu(0Z~6zt2l+`7+E(LBIPjH;No4}IeS#~stC*S!Mfvl0C@^Tp)0#u?g)9cI9AI){H1_|0`kV2z YWYK$mC%!Hfp@-x1x>*+9f&V-I2PF#wYybcN diff --git a/src/site/site.xml b/src/site/site.xml deleted file mode 100644 index 2a5939dec..000000000 --- a/src/site/site.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - http://oasp.github.io/img/logo/oasp-logo-72dpi.png - http://oasp.github.io/ - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.skins - maven-fluido-skin - 1.3.0 - - diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml deleted file mode 100644 index 3abf3d444..000000000 --- a/src/site/xdoc/index.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - OASP4J - Open Application Standard Platform for Java - Jörg Hohwiller - - - -
- Welcome to the Open Application Standard Platform for Java (OASP4J). -
- -
diff --git a/oasp4j-templates/pom.xml b/templates/pom.xml similarity index 94% rename from oasp4j-templates/pom.xml rename to templates/pom.xml index 3fb002596..8c08b5ee1 100644 --- a/oasp4j-templates/pom.xml +++ b/templates/pom.xml @@ -14,7 +14,7 @@ Templates (maven archetypes) of the Open Application Standard Platform for Java (OASP4J). - oasp4j-template-server + server diff --git a/oasp4j-templates/oasp4j-template-server/build.xml b/templates/server/build.xml similarity index 65% rename from oasp4j-templates/oasp4j-template-server/build.xml rename to templates/server/build.xml index ff0ab3477..05bbf1c88 100644 --- a/oasp4j-templates/oasp4j-template-server/build.xml +++ b/templates/server/build.xml @@ -28,8 +28,8 @@ --> - - + + @@ -47,9 +47,10 @@ - + - + + @@ -60,8 +61,8 @@ - - + + @@ -72,8 +73,8 @@ - - + + @@ -81,15 +82,16 @@ - - - + + + + - + @@ -97,13 +99,13 @@ - + - - + + @@ -119,14 +121,15 @@ - - + + + - + @@ -142,10 +145,10 @@ - + - + @@ -156,74 +159,27 @@ - - + + - - + + - + - - + \ No newline at end of file diff --git a/oasp4j-templates/oasp4j-template-server/pom.xml b/templates/server/pom.xml similarity index 56% rename from oasp4j-templates/oasp4j-template-server/pom.xml rename to templates/server/pom.xml index 5d206d93d..71eb7abdd 100644 --- a/oasp4j-templates/oasp4j-template-server/pom.xml +++ b/templates/server/pom.xml @@ -20,10 +20,10 @@ ${basedir}/target/archetype io.oasp.gastronomy.restaurant io/oasp/gastronomy/restaurant - ../../oasp4j-samples + ../../samples ${project.build.outputDirectory}/archetype-resources - ${sample.input}/oasp4j-sample-core - ${sample.output}/__rootArtifactId__-core + ${sample.input}/core + ${sample.output}/core ${sample.core.input}/src/main/java/${sample.package.path} ${sample.core.output}/src/main/java ${sample.core.input}/src/main/resources @@ -34,22 +34,13 @@ ${sample.core.input}/src/test/resources ${sample.core.output}/src/test/resources - ${sample.input}/oasp4j-sample-server - ${sample.output}/__rootArtifactId__-server + ${sample.input}/server + ${sample.output}/server ${sample.server.input}/src/main/resources ${sample.server.output}/src/main/resources ${sample.server.input}/src/main/webapp ${sample.server.output}/src/main/webapp - ${sample.input}/oasp4j-sample-server-integration - ${sample.output}/__rootArtifactId__-server-integration - ${sample.integration.input}/src/main/java/${sample.package.path}/test - ${sample.integration.output}/src/main/java/test - ${sample.integration.input}/src/main/resources - ${sample.integration.output}/src/main/resources - ${sample.integration.input}/src/test/java/${sample.package.path} - ${sample.integration.output}/src/test/java - ${sample.integration.input}/src/test/resources - ${sample.integration.output}/src/test/resources + @@ -68,7 +59,7 @@ - + org.apache.maven.plugins maven-resources-plugin @@ -82,47 +73,50 @@ maven-archetype-plugin 2.2 + + + - - org.apache.maven.plugins - maven-antrun-plugin - 1.7 - - - ant-contrib - ant-contrib - 1.0b3 - - - ant - ant - - - - - org.apache.ant - ant-nodeps - 1.8.1 - - - - - copy-sources - compile - - - - - - - - run - - - - - - + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + org.apache.ant + ant-nodeps + 1.8.1 + + + + + copy-sources + compile + + + + + + + + run + + + + + + diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/META-INF/maven/archetype-metadata.xml b/templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml similarity index 70% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/META-INF/maven/archetype-metadata.xml rename to templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml index ed50777e7..070e9378e 100644 --- a/oasp4j-templates/oasp4j-template-server/src/main/resources/META-INF/maven/archetype-metadata.xml +++ b/templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml @@ -31,33 +31,9 @@ **/*.* - - - + src/main/java @@ -73,7 +49,7 @@ - + src/main/java @@ -107,21 +83,5 @@ - diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__earProjectName__/pom.xml b/templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__earProjectName__/pom.xml rename to templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java b/templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java rename to templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/config/app/dataaccess/NamedQueries.xml b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-core/src/main/resources/config/app/dataaccess/NamedQueries.xml rename to templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql new file mode 100644 index 000000000..e00a65ad4 --- /dev/null +++ b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql @@ -0,0 +1,47 @@ +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (101, 1, 1, 2); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (102, 1, 2, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (103, 1, 3, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (104, 1, 4, 0); +INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (105, 1, 5, 0); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (1, 1, 'Meal', 'Schnitzel'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (2, 1, 'Meal', 'Goulasch'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (3, 1, 'Meal', 'Pfifferlinge'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (4, 1, 'Meal', 'Salat'); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (5, 1, 'SideDish', 'Pommes'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (6, 1, 'SideDish', 'Reis'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (7, 1, 'SideDish', 'Brot'); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (8, 1, 'SideDish', 'Knödel'); + +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (9, 1, 'Drink', 'Wasser', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (10, 1, 'Drink', 'Cola', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (11, 1, 'Drink', 'Bier', false); +INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (12, 1, 'Drink', 'Wein / Apfelwein', false); + +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (1, 1, 'Schnitzel-Menü', 'Description of Schnitzel-Menü', 0, 1, 5, 10, 6.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (2, 1, 'Goulasch-Menü', 'Description of Goulasch-Menü', 0, 2, 6, 11, 7.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (3, 1, 'Pfifferlinge-Menü', 'Description of Pfifferlinge-Menü', 0, 3, 8, 12, 8.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (4, 1, 'Salat-Menü', 'Description of Salat-Menü', 0, 4, 7, 9, 5.99); +INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (5, 1, 'Cola', 'Description of Salat-Menü', 0, null, null, 10, 1.20); + +INSERT INTO RESTAURANTORDER (id, modificationCounter, table_id, state) VALUES (1, 1, 101, 1); + +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (1, 1, 1, 'Schnitzel-Menü', 'mit Ketschup', 2, 2, 1, 6.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (2, 1, 2, 'Goulasch-Menü', '', 2, 2, 1, 7.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (3, 1, 3, 'Pfifferlinge-Menü','', 2, 2, 1, 8.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (4, 1, 4, 'Salat-Menü', '', 2, 2, 1, 5.99); +INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (5, 1, 5, 'Cola', '', 2, 2, 1, 5.99); + +INSERT INTO BILL (id, modificationCounter, payed, total, tip) VALUES (1, 1, true, 14.98, 1.3); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,1); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,2); + +INSERT INTO BILL (id, modificationCounter, payed, total,tip) VALUES (2, 1, true, 14.98, 1.4); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,3); +INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,4); + +INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (0, 'chief', 3, 'Charly', 'Chief', 0); +INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (1, 'cook', 0, 'Carl', 'Cook', 0); +INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (2, 'waiter', 1, 'Willy', 'Waiter', 0); +INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (3, 'barkeeper', 2, 'Bianca', 'Barkeeper', 0); diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql new file mode 100644 index 000000000..a070e18a1 --- /dev/null +++ b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql @@ -0,0 +1,2 @@ +INSERT INTO BINARYOBJECT(ID, MODIFICATIONCOUNTER, SIZE, DATA, MIMETYPE) VALUES (10, 0, 72861 ,'89504e470d0a1a0a0000000d49484452000000c8000000c81006000000fdc872dd0000800049444154789cec5d077c5545d69ffb92d04297d8404db020c15e028a9817052c5850888b65dd447445d85d753fb16b6eec8a5d41455c13171509764511352f7614ac80080a449a0816a4a4e77e73dffccfbc37e7bec90b5d77f7ee6f3d9c977bcf3d77e6cc9c32e7cca48aff5d9b731d618174f552c00114f9cda4db8bc16d754d6ee67d7314f0ca4c9cff3d00e76e2a63ffbbb6e945726a9343926b7e5fb2eb8ccde26ae32f2e7fc92ec8b3677b8eff5eb6a98cfda75cff5320cdbbc280ae024e1ef0df003b00ee88bf17b3e7803b4e92f7d0c0a48976de46f2b9b9d7b30a786e92fba6e0be29e6cf5e2efe41fcaf06fc1a10dfef95031fc9eeffdfb56d2f57012daf7451bf91bc925c5700477f3ad4afc39a7e8d83f78803369ec5cdba52009b29d7de7e0a3ac9e49afecec6b357847f2479cfffaeffd42b0c185180267c0d31d042c04310cc140ca054086cea4d0aa6a501deac608b1680b798b0654bc083016f05fc50c156adb60e24fafa7dc7317e5a327ecfc6f7bc0f38c0fc5efafe941b01430a866e50902620872bd4086058fcefda1a571830a280966718425aae8f5190fa8dfa3120d7e8779283160301494e3e5050cb11c9d5ef55ae312e699cd2b8b5c935c97340aea93d49ae5dc0b0f80fbdfedb3d9030a0ab80f62c4820e83e36e139c702920091e52205eec4d20b96b56923c49ec507cedae502299cff6a35a0ad540ca9d35aeedaee2d298453437f4e4f9737f7747af802e81ded558b1931961c57fecfe76b77d128241daf44acf7ffeefc2caec02d51e8fcec98f815c0afc07da728dc29717e32bef97871a46f29354ca83b61fd7542d416d7fcb6f63221aa2f5c377eddde427cfedadb137eb84b88f7d6bcd0a3bab77ac4c38012cf032708cbcc7b0f1003cef300df357141f7870129a451c1a063d2d70ae67f57f3aeb0020e6f573ed145f03b148743f046f3795fae8767de7a48468610ed4eeadca5f34572926ddde2fc761ba45ca7a535b693cf39f3424b5bc909dba9768ac4c742349ed47843546ed738a3a3445a8a1ba372bd9b926bb1935807b96f9e3c0bc8b31e07cee5d1fffea4f0c6eac6f7ebea84a8ffb276e9ba57a45c2fa89ebd6e9d10bfcdfbf9e835ff924ec8b47bc6af947cff72daca168d6f290a24d75a6e49de489e09f6078422d1f24d3064b62f89bb9e40e8776a6f1790f03fec952ca4f29f7665039242a009cc054e03260218e781b4bfa24b17e71d212e587ddbb85e6542b46dd3b9e4d46952213c99b2c721df4a6ba45de8f283baca7bf70a3dd8ed1ce10fca637c0523d54104ef54c336ac70e9d62b3c0ff85c312a8af7528101f96b187f575c8515ee54e86941e111e079b83fac70799f8bbb8a814780e7a9f703cf1379461b79725c1c2dc11d8d5d974c9403b35363ff05e3e5803cacbacb872f09b17cf477e35fbe5d8847ca479ffacd3772c05e52bbccbb5e3dda08179e42548dd79b38b9f88d6f037f1010fdc207a61e6080ff5328962bac80291971bf931cbb0c9713ffa90ffcada1cd1d52ec86f46dd7f74839cfaf6bd3ed4cd9dfa195a18b7bf490f08ed08bfb3c296fbed2f9a5c3bdd17714c7539352a4702e7f2ef062c24d794b302e5c3c077a5c7e03f21dc1572a7a118b3cd3f59e1853552565af5bc3830b779306d47d0d5fce7f5488758dbffee5f97f08f1e592770ade950ae3c5cc07effdf967f5889647926bc8ad96732ecf24e7d7b3e7c38024bfae79ff1f57a1fcb72890b0027a8061f1cf41ac375e6174fba5c7d490b49ccf9973dd5b474b0bbde5fa36a9674b8590727ecab24172a089279d3332e6c64dd0d910f0af930834298e0a61d87ff2bfa448e6021f053cb1e220dc351587c68bf1b5f9186853028ac4059fc5e0d3051d1e096ff2f2def5fef2a3b4e86a8baac3af1f21c4ea51cb9e9afc8c100f3ef08fbf7c78bc1035876c98d0d04fddab0718065603299ca1803fe0ef3400b985470ac535effbe30ebc2d746111376008f1d0ab84e7ae2aceedd041883dceec396cc810e9391cd562c8b07952417c18fab4ef1bf2a6a39c375adc6a18244a1e36da7031479be32491b78d378c22b82b0fb8499f29ae665fbee124e5b2e1a086215f49b9ac9eb86eda0bd2d39efbf6870ba64c11e2e9cadbce5abab7ba953c98c646402886c6a31524b9df648512de28ceb7e3f59fae40220ae8d014b227686085fe2ec45f6a6e0c771c2c3deb8f7a9c34525ac2a97f4d7bfcfce1f29e5d9cfebb2d147605908d097f0ad4d128780e6e12cfc1a600ca809fc13c94e2c080c157255554a3807f0d3c8caf570331b987b34957e3418d177d5f2ac4fa9fd69cf2c47942bc7ec0e315fffa8b101ff678e9a33558e3696800dc17cf9c0e9c069acdb223c807de7fcbe26518d055c01907488610290c2909a3cb4a2e3df06221da7cd5eefacb5e91b2fe51ca8cc1f7c83f5ee3bcde6a4693868c033c0cbc690fd8c5046ef3b08b418f8d8b0413bda2175030f04c2a347d07385a63ebcab39c4322bea2a89f5a7bd4fba942ac1ab674b7717244dd79eef997bd592f656f60e3cb0d4ca1d41f059c0ca5a34dc83d1aae58fe381e77687b33b085afb0027cd19bf4a4bfe670f6e1d7f56ebf548ea369cf7c75538a1099a7f55af7dd04e96134a6762ff645746771acaf38bcb0a7a81509356d45142e3b55e1655ed47e96ff2dc3dfa3dd2def8a44f172747f44e15e2ec3c3c0cb81e78b223ca7dee32a5c3e17c6730af78097030f6bbe8a0c3e87629a21be72357de253e1459aaf22834f21c81edaa82bf479e8a1dda5c268b7a4d309d74a4531f4c54bbb7e768a103764bc10bee66a21fafe6df01d3b22aba7e58b0aa66111360db1e894774d18a2c5784c0521f295220ae829e23f35add25540875809fe4941bf5d464f2e2dcdb95c88ebcf9cf2f68b2f08913ebb43c3cc41f29e502832cc4ff2a815aff98a2320c7246f618d73f950d35b4cfe144ef2e7327a11462fc2e811fd987c937f69c833d10ff01b93e748b3f8cdd5fc6e923cfb8ac897bfd43b5aa4f6930a629743baaf78ba8710b7674f7bf46de9698c4effd7d7a79e2adbf9aa50eb5658b40f2ccad3623cc937d65242b496fa0e2019ba11e0866afd3d5e29db9b812d74b90a38a50ccf5230243be8f2034abf3be61821323eef5659faaafc2d2b74f219afc93f9e25766b3922cea2c914a6055608fda32d1ae0b94ed4c2971e880a20643825782e338ae7295c3e95a99e032e804780e70177912c59a83c1a892beeb3c88557b87c2a8ce7b2705f18f765197c4e15e90a075f64c1656a3e155ea8f9cc637c9a1e0ed1dfc8cb0939bd5b494fa345bf56e123a402d9f7829cefcf7c5888bd871dd2ed2b69817d32e1f52f9677c5bde729187a023838d1592d05c023c02bd9cb5e05244552b2291cff8eae88024e21c3e5771714dcf846875a214e9a72d1f0b1b365fbd6b5aabfbfb3fcdbbad0ebfb3c1dbd2d4fca52bc45afa8c42c7a856792e50fb9ce0bc8877a2bc94725f04cbd96a1e86731fa25c00b40af447b382506bde41eb5c96f4c9e33151f49f8ad60fc4634bf345d6fd2159a93b27aa72ba4a1744ca7f5833b0a71ccddc3e6f6a91662e6fd6fe4bdb45688ea97d77f010e63f28c7ea47989feee3039760ad8cbe8ef2e60647338df92d71f5d814414e0032c24f11da675ede47b1c173ff2f0928b074b2be08456a32748d7d2e928fe6ff7cb842f8833a3cf6eac2b4c782926d47c087819043c4f2f062a3c4baf4144713900159e093c160250cf459c3151bc10d3656c00293c532f5e2abc50d32f009f0acf56d92ff22b2fc7f7d173cde3b3c49c789c32e0bd366fe039739dddda48cbb8d3693bfd69b0f4040fab1d78defa3942bc77d0f3fd67af97377c2c9ed116363c0fddbf61e018507aea590c380ab084c1c50cfedeaf8802da838e33844666dc5bbb4b8d103bdd97b5f76bf2efa191a15927f83ded4849f27b46cb99368894a14172ed3043a3848552638ac48de25a3eb421a30cac126d6099f42a809362aa04bd4c162a73f8b8b018709c5f32e0285416534c8c5f2ecfa6e1a5e955f2e97bd3ae94dcd4637797be50dff5831f3bbe95103b7f9ab9fc0be9617f59f5ce0d3f7f2af0c980590c87bc9342d10a02bf7b7fc17d6c9edbfe06d21f2d84155620517dc60e27ef7a89ef1a5ef1d8c49b2f9396e8888abbf3abe4d499724beadb779e246fbac2dba7e521712e385c5dc2c9d5952eb4f1bbf5be6c06c3faef70d1f573b98c4eae41c705de53d309b3f787d9fbc38ccf30a3aff0fc24df97cb20bdcf765fbeca95dadc10175dcefdcefc96b709d165c7aeab6e7c4f88bb9e29fff3a27385b83a34b174947c93b3a7f36afa27eade361f2bd8fa76055ba2ce200da18254d425a4a0f092425d8101ea6e0ec75bf17215e072ed7fc788fbef7978974764bbbc30e9dee9470ad1f9c25d5f583a51fe7181d3eb9056861c303913a69c858173b9e6fd6c9563848838bddc24e3c43ebe368d5f3bff4d8fbb00bf0cdfd41017bb52d3d21ecc96f27bf0b5c7be37ed2a21ee5835fd377fede4ac4bafbee4f057d43de92a36a0e5bad5f10a527d4a1ae45b87bc28bd9a0c0a2627342f6efbeb8fe2818415d01341448190b43d8e4a39addc8f399ed6f9921f1f9d2f3fa943eac4ffbb2cfae7f342c3e35cd60258f8e3d00d8360afc203901e45a67a9776b9159ec742539570c15d71a2a2a7435cf9e0d1e8d69845c72c38edf910ae426222839e33435c01d7ddc6a70bbc58d5b54b5c2df2f31017b71423c00b359f59069fd92a24e6ccdcb2212e7df51367a7ec2907d5c0f61d730b8438b2f4d495bb5c29c4274fbdfef67b7200d6fd5253438b8f3a04e0022a0e847707f0b180e094f2ef7588b3c07c6ebb5d78bfe6ab44015faeff71cfc3693d2609d16179467ab954acce0fcee107f96b46310f7843f4e67c27fab53a6444728610a8bc2f0ceaa62762f5b059c888cbb14d3e329907efe8f45d176f2f34e8337e93876c897e9210977ddc317e81f390dc9692675ca12f535674bc54885dd6779f709a84596fedf7ca37c3849875f3f44796eca5eed11e495e621a7c319df2ceb45c43b1e89e5ebc25386fcef57b5720a80f50c12661288ed39ebbf895f4b652d31fd3bfdbe4d6f2b70ea1be43fd18b86dad8026e8b0521c7a82aeb4645971973b8fc5564b31e0b2a13866824b5b6880b2aef400c18020d73d177caeb684b8f800d4316c169a2ad4aebc7aae1821311ee2c2341a17232f60f44dbc140561f92a241608716da1d8325d2d3f69dd61bf9385e833e1a4437b7e24c4d7bd679c551e1162dda45f9e6df8b3ba470f38c569ac9e84f6682a31a107c84362db3cb4e5323e4a14f0e5fad2d327bc947385b4521f68b7ea8db3e48f473b3bef72b508aea5e5a2ff660a55c6aa0d01c859a596b3e8dba49c15a8fbb4bc642a26f85a1d8d8766cbb1a25702fab15092a25fcce8050c17d02b64e322a6984c7ef39284e42a412fb399fc16b0905c1e70572bae4ab1052ea79d33d0af70ef727ad76306ad1262dff29c65cba5c73163c2ab777efb286e2295b5185071a04358f4bb561c61866f7345f27b5720aaeb759ebbefb2f51f77eeedad4608b1ffcbfd4e7db1a3ff5be8bd81fea2a17d714de13958a476510f5d29da466120b64a038759302e048b2cba7c65014a8f661470d0c180cc648be585164f42683cead1480f643ff01dc673598c4f12b330eecb32f80c93258745fe584cb8047f570ab0447b380a77816769854a7c293c171ecd4c78343cb6be9562cb69b35aeeb0e7b1421cb25fffcbf6972a7ad67dd3fff646ad1035376fa8e079f35e4fe087038f002f31e1761b706410d15e4ae0c3571c97ecf6e88043d709d1eaa3f475d3fbca1fab9db69d3a095feec860898057c255126f3e0ca29842cf54f7b1fe136cb1991b44b1fa8a02e08a5e72392683cba45fa80db002f57ae6f1307ee3e42fb3297e35bda007a5e871c32819bf31c55a01fa61f06fd2afd49e378dbf4dbbfa8973fcecab8e13339e1d203deb1ee71cbe6ed92d5291944f5dbe00c9247c2d84d27ff9da87a738b57b245bfdfabd2a90b0023a0b474e1cfb1edafbdad41be53c76ceb09d9e901de0fc14aa3ce96f22e83904f3da155e06415985e18bd08ef624b82b6fb7e894a04d45b7e5a28069a61660d322b765bf04b355c6814f2a2474f11d8a6f872d9697989e439ca7021c218e6215e210b49858c13c9cd8402b34db8185e22a40cf926da62dce2c66d1966c999040daf72d4ede437272e84e037aef2e3d9077339f7bcc27ecbdd158aff3ea115bf6bae0a102e02ef00860097e07becd1409d56d60b1df571ca3fefce02b7b2f971e47dbf69f4cf73d8dd9cec79d4e8ff3282bd9623059e6b92ca4c843300ef3ac2bf5c4e9aafb40dfd1868732902a028686a2c72bc8b35808a9c44cce207e831e8e85dfc266f2cb43ca4e52c388f31b01bf0a2f481c0a0ef0bba543b65231fba1ab8e6376bc3b4f52ec76fc3e977ebdb3109fcd7beb8325efe29eb002dee326d4f24b38c1c59ab671dfd65b6cffbd2990b0023a0b679582a1ef653fef78f3fa3183e4bfbd50bff3a422117031a547607a0e3aeb435be80a1f8461ebaab45ba778e3d26c039e43bef268e4b49f0b5c790e2c7416c767624f2253e36afacb09585ec4679ec1676c002abcd0f41c4891c8e7f603fd30be2fa1e7104b070e588a0a2f08649b450c3e93a74f46f0f6cd1a782d17b45edf437aa087b43bf6afad3e948ae4e5e71efd4405e9627b735d04e89abfeb104026231a062c002cd91c0e135ca0ef4c0594beef79336fbdc9df5baad3e89d2e8ff80af06ef17ad737a3f2a3dac7b69641064c2926eafcc45973564320e0b1b290514c91287ac90d0d538e89bec3c69f13480736e83797dfb82c3193dec61a46997cbe08648935c9ef160bd91e2d3d923da55df641d773fa4b8fa4edba0e377c749b105fd7ccb861f549ea16ed81907cbbc00b184e8a2413300258c2e016bb7e6f0aa444010a7e84e440bbe41f8fb61a72bd64759fb49bfd6caae8c4e78b5465920a59be15020dc4626ed1359dbe1ab7c80e41043e1591ec5c65bf4a2f4929289e665b6949b3e5ae760ed26e2348bbddc834dbc000c947086baa9e284ad47396e48042aba5081c21c01c786e1116e2d3138f9e8e1ddc17c67d0ebe07f8e685b8dad4b49f7ec8fdd2723b719f31f3a649cbedf5b71eada401471e090d382a557381534cb988118d009630b899974e3b960651b7a77bec9422278a9cc8a04e9356c81f478bb2c3e78a449eafe2b632b0369519c57361c0d8428a3c64c4d70688be635bfb4abc961833882c86464c3131fa01f9d8347e631e2fc68596bf84fc26358c821e8e8bfb0a9be4770b876c9dfd9d65fe1ac9ae1bf67ce3882b855878d897535e953eff2f7356de545d8d9b10b2f588a3087092ef45c04b80937c9702d2738b3787d3f8ebf7a2405c05e20b6d865f7d5bddce774bd7fe938e4fbdee87ac16887e7e419ad5c58c854c144e9e0362ab729a3f11ef52825c8a8167cbce2041a9b4780ed9ba9010d95316cf2116c3263ef3189f0a2fc3692083f404adde53c806888d4f3e00a712df1b991c602bec2a80c22b43b2c0c62eaab2ba15f9dc68d0d9b463861c650b7629df7555df3a217ed87571e3cbd2725bb9b872ce06b5ba151b5805c049a1ec81df6940d2df29df3e0f7fa7cd37576d128746e19f7ff99ef4f9d78c993c7aacfcf7e9a13347dc16e74904e5577141f25bca4230a5f8aa0cd433e9898dd1b37bd6444fd18f6d1552095cd1b31b44267dbe56e268f9a9041e06fd0ab48949df05fd2c6d6025e437e6f1327a317e2b8cf6284cc22f85fa2c1e9495df606859d1ab741cb1195768ef942eed2f16a2e7b23ec7ecd1284568ce336ba6d7abbfe92d7b4a80ff85c14cfc7d3120c97744c12dbf36b2bd154858019dc61851c0df3a205c3dec9f974b8d1aaa09650cf0b7baa0892e3621bba0014bc1e262566a4f42ad3114e318a3b0ca4ed2169760829167f11c08d769948a9e54001be29fb3c7b0399f68854158944f163a13cd5c83c8469af14c240bc442020ee887f19cc263969c83b784711f2c47840073b445a8ded3dc4555168a93efeb055c29cc4db4e09ccc502bff1c889dbfc93ca4aab710ef2f7ef1894fcfc41f6960e55a6026eee303d3054e27ed453692a93078c380f50da2bf5e7cf79cdda527ddfac1f405cf4bc3487cef94f869e601c5cd437e956cad81d6d0682784d57a622b51cf594330067dab67ad4359da63b51944d42a26bf2cbd564a8fcbe867a2554c7ef98e08b6f4dae09a5f26e337339e5fc7257963ed51a2e91780be1b4f3f29bfb68a7a9a1f36d32369d9adf569ddf714e283da97de2a95946a1757fdd688ec43ed41bbc01799bf6b1c7f0fc82fbe68f33d91ed5d488845456a087f517178e11d859997cb0eb83b943ab23a5a2814cdadf18abc0c752ff09e48d61c0bdc53b8bc4fe161e03d919b33dceb13c5fb20d973ac17567f47415111f0b0898bb1820afd143e12f840a22bfae07dc467b681f7d4ef233eb34d3e9502f22e1543f15cf43bbda198d6c602efa9f7fac9c073268ebdb4e4fb543b4d10c38def9f8cf7802f79b7c2f3894f4458476abea8104be1d9f88e22c6674f85c7f13994f1893dc3c0d758e07dc047ac7d894f1e586ad695f1efdd479fb58310877bc737ec8182c3560b0171c0508b73144cfb55413f29c3bf42df281838dfe53110cf6e2613741fc9356dde29e5baed9c8e7fbdee0ef99dc778f9a9efc7b707f65443bfc5c92fe480da09f2ec01773dd5bf28f0f3747b9bf4347dcfa42f9f37c707d1efc9e42e6cd297eadea43f99f15b64d2a382bdb8f1c6e538b17c107dd61eba00d065f4c65ac685cbe88d34e557ca5b2ef07093fc4e66ed61e33726cf54b0b849f24cd725d5e32aaf951e8833cc59d11a5bf5b47e59413a80ae05b2b7b85ca71cab6008597f0ef6a0d3f2b9d9d7f6f2405c05f46ea2ca691429ef48c36acc9f163d2b159bf3b2f3dbbefe80a6900c59fcb00bb5c59fa32dd90db88fecc60db84fe1678a5fa2f8550e85aea27469fb0b692d66e277013a0acf005e067c10a8ff13ffaa95ff13069fe98ccf74c667bac127e1d761bac9c722ff6850c991fff371daa6a358e1c4a7b4c072189f0aefa70eda9578187c636f2cbc370b7886e6330bf7115f59b84fe1282414fbd19bc05719f0189f198ccf0c7c4f0eee53f834b45f2f1520927406e1fd8bf15c41f4f766a64f86e6868e6bb59310ddafdfffcebd3e95defbc2499fbc7110fe488b8b74fe088ed2d5a12caa1ba1b4609c0def41f1e8b62e698a0311db5e1d9bc784ae10e2c26fee796d5f3905b65cda7aef470ef16939e3fc73389ca9d46f2804a47eabd4f54a9003edf9a9509f8bfe58a5e439ee585ab437e88da1f6d65978aa7f4ab52429fa65267d87f611cb31e54cca2bc95986c1ef203cc1e967805f0a076620c443f40b997c4cb5d02f34db234e0a329be2578f0bc1f9857c825f3d5ac3144283fc717e07b1f6b0f19ba343d2617ce7623ca7e86d645662eb5e6d2bfd7359ba8dd8a76ea91cd19f3df0d6238b60207998e93c54b87b3f02c213a1dd80057674f090deae0b6d0b0023cde124d1b59d14885eee2e51c08f0d8f68bcefec7ef283d3c6b6ec71bddf00d95428d574819e70292bc51ab3a41829290e35614530b02a2d69b622c9e25a2c0f5f85b0a6b2823d96661b17322860ef53782e14de4cf065cd26e17c5a43534ac1165a425cd64d1dcd7c7c6fbc77ac7fd25b6d7df5aa5f779122735ada9036a31384b874cc197cc4d68c1cbccde433072118969e2978b6d946a64fb6d8bb55763769b1b5c86ffdf9c7270831ffa5992b7fa42c2d3a10687740da5e1b8a446fabbd8709b5d110065ccc5e8adf75c80a7ff743b1fdcecfef30460e6ca7ceb9d8af2497d20c4388cb970e2166a9ef27f9e56b72907f92a7e2666e92e830fa9516fae84f6b882b58f1eee03e937e89a60ff9481ce2b28f374b7b8441cf16e27218fd60c5bbfabe2c8e379dbedc5c7e25be58e19610d726662576d8a3cbfb590572ae7fe999752fbe2465736de3127d901b9d4b028fbb118650e3b90a9afb1dcbdf6150e942d64dbeb6b5027115a0652682fe59cc7d1f3e7d8f47ae94c8df9ce3bb0f8fb3649215e8553673ad2007b6046ded51890aded8449765e0c9d2295d780ee3b48554c8f8cc637ce6313ef30c3e4991f042c264e9c0b64ae16226e0c9765565f9f8cb977c37f35d39018e9f76f9f83ba50bfcdae0c786bf2227c2da11d5dfcf961371e617bd2a0e90967ecadc947fb43a41d8d78c2c15efda831c048bb9b99b3a264f9f8cd62677b96bd7e37638540eb85f9e297d13e73378ff5290ce19a181a4cf6bd8ddbc4f57b6e7c67f89087a22c0f562b984e7e5dfbe47a684ad32d3873df2bafcdb27ce14ac7960cdc75291cd176fb5a2c677c310908a830a6351cfd4b45c2438f0c955efb5243bd8924738bf9516fab4d8ece8f180fec3df5141ee7dea0da9f70b275778cf44dbff48a7b79fd66a6d8f40d624537cc9f8658bef0179b3ad51062ade2df429bd3db6f6c2f865f2eceafe85f424be5217a6eddae9342176fc7eb7cf174945f0c5b28af98b17abbfe903da48aee95c1dac859082d16b7f8b18f102c048531c24bab6b10249e4790c5f3226fd40e99ab538a4f5c5b71f0f01f4bb86b6f6d8dc023d1a1865505fab90764b27fff102bd98001518efe3e994a5420599b2e1d190e760e33360d16945a504bf0016799916a812f099a9de9f24cd962d6a3b6c7b7841969b9e4098e78001f853edf27f7f76b7100fdc3f6a8f871e16a2aa68ed71d5c3d4030d3f08f1fda3732b7ff4cf6aefe2a52f385b883d8f3d78515e963160884fa59878b619f13988da178a5c0fec24167833d3275b6e685de1171cae3ff9b7b96fcb81f3fd075fafff15e78fd8065c23290e0a0150653b425ab6cd18290924def3387a7efe946bbbc9df760cbd78a4bf5545cca3863f1450ac99eabb9821c417c72b7532897abe9879e836f97518fd4a6bb24325e82b7ac1745d93df589698491f8befbffe75d59b73ba08b1d0fbbc6e9a94a70fc6bc745a991c3191479e29f6e1d457c6ffe519d9ce150b262ff18f969d77e327d3a73d22f5c9a3df1ef1ee5eb2af4e6d9cb7441a982d8e6b55eb9f0fd332adcd313b0d13f6ac2b7bc5bb6a0fb6f81e935b3d2e98bc252d1730da63a3b32737b2e2bdfdf22e37ed2447f6dbdf3e5df71ad27bc9d3d0903c11e6a19047ad3d6f78269b9e9db5ad1488ab802e1044d3443d8f6ea77d769914b0d017a1257d8e1031019c89b4dbf06616e85187c60a0915ac4c1a322901a6048c7b0ef9caa371c66182b61412dad381599e3bf19db38969b6bcf2b6580f1835c16469cbcb059f05a01fc5ebcea969f5ebc542947e77fd2f77fe24c4bad77fb9b5ea35f5223a71adee1a05eba70bb1b870ce052b6f97e4669f5179c233b2ff86a53ceb9fab62b7e4b8e5851060a13e39d1453b1434c56720dd9314ea547542a4549b3be2bdd137b77fa5f3e55539427cb8fce57b67dd8defc191a30dbb29a8435a8d26f44600a7ac977062a83d6aa9480ebea3fff8162be4eb67ecdf6ac2b5f2c74b4446dbb651c5617aaa95a6a72a5c9d9e4bf216c1f7e7c57fbf80a72615c738e06a0dab34a9fc2a7af61d1b5ce0eaabec068b29776c2fb9eac675bb2ebf40888fb35e2ffa979cd0260dbea572f22742cc7de1c3590ba442fde1c64537fed44ecad79c5fe76cf017851bc4f4fa057e238b37ebbacadf1ffbe57d7f7bffe56bbe1bff93f47c67bff8de937e9dcf8737bff48c5f70997e4687d3174ac5dfa5a1eb375972fe487d256d40fbf64204f6e0ca4a5a70abf8d705b7d6745d458f57d4575ada23a6a82a403f0cfa8a9e6dcfb0ace6856cd3f66c79d68e52d2d7ecba7afadbb21d967e3e7fed9a2fd4df1ab96144f2bc7b62a843b111c030fb3de9b5adb3b05c05fc0197fde491e3fc13bb4237a4f43e7398089ea8d7939da8c74e34132e3b412f76629ac26327f65156959ae85d64a5509655849dfc579eec6434d02f4336d550289088de369af83470bd6db4ed64b76c64af94e33d31bec3463b683e3d337b449ff406bc48f1a5b7b7e6ed1bcb568972feeef8673b3f2c2dc41f462f7af89703a37f11feda877fd51e09788a823535d2f618975a59eba70f3ce2ecec677b48be5cc6a7cbf874f13ee293b27458fb5af8a476099ed4188df87a433d9cb06e5e3bb6dcfda601ef4b393b3ca5550b9c7c48d02fdcf2afd45440ca5ea16c2c828e4953af7590e516062ea78c3ea9a7f41ff87e344cb072a79de2daa327b50ff8f5c03fc91765156979a6ef2779c6f32e9767d0a3f6487ab29f0e6418f4253d17bf96030f1bfc5ac687f741e3098d52217fbdef87d74cea21c43d2dffbae09aa38478ebfc7faffc049ba0d64d57b0f62a056b8e50b01ab0ea4ac02a05375c01b821085f39e1e1fc0ad92f631a0a8e1c31497a36f3bfac79ec3bc9c780c69b7d3ebc64edc1e42d0e57e3c463f21666f42cfdc7db3be9b88bc933e7b7dca0173c3621bacad3e79293fe791c9d8048c71ba499509fec896c2c92eb106d0f4f72ed32d8ec6b1b7920daf38828e8bbf8837b5fd2e318f941a98569e32fbc4d04d720289b293f693e7a099e53b8ad10ab582f66533d48f30a0979c8843c876c58105370767386c573e079f396453a67aea2db785fa3e74fcc553bac9bbde40969695cfee3a039d252fb6ddd4fcb16f41562fde85f572f9296c6bab5bf5ee9c3aa9cb5af2cd9533eb8d4bbd08f25a7b44bfbb6cd6449ef84d08ea917f8efc31a8325c4b764e9bc6b5e3d4c88672bee396cda1baa7feabb2958d71710bb85d67604bc5a88d36fbac4c9919662d7017b753f4e0ee4384bcec5fb14ce0baf62bb052b0fb3d8b2a9a50e11008f2daa3ab8cfc4f99a19da37e5c4d453da4a8b37343de5e799d2a25df0dba75faf6cad5ea03d10e4d737c0b56fa0b512a44b36926a5a0c1811c6458587fec03c62d4a91baef50f2e7bdc396bfffde3da23e651b755fcd93cea2415deb1c5f3d1b86f83d11ec92aa66d3b3654b2f6b6edc185f1d1b053dd90f5526e2aae2913f7490bf88d6e8f77fea0859cf84a1abfa8c39a13c951edae800b14240552b30b7e27c57235f04780cf57b0ee6cfc0e58ffad7cffabf5f7fa86cde7bfbd3d66f63a21dafcadc379f3a4c7bccbfdddff7984348442a9ce9d2d2e4cd01e6c735289a9ef250fadb97b8655b2f9c2d5f4d5df5ded4134e9513abca25eb0d07226e1a647d2eaa3f4fb3aaf918afafd2797bd78a97a904257b45b3585640936c03321b9d79b912e0674c5465e5b5b81b80a6805028bcd5ffbe8b3eee409e74bcb2f549752dcd79fa8f81a44aea013f594fdc13b3469819e5ebb50f7bb586328463a60330bf4f4a2652973614b112ac95779dfce6a4c84997c20269ef8ea47d435ac9382ffe382ca3bfdf32ede2d7eeeb5c7e54435e5e33b4794e408f1c1292f9cf5e63942ccfc7ada981972c2fbf4cbe90fcfdc4f8859def4b299ab25ac7a63d1277f937faf78fdc78fef90f72f7af196e913249d82673f7abe83106b1ffbf9838fbe14a2ddfb9dbeabdd5b88d617b7fd79a7a9b2cba7a78c6e257d9d0df7af1db0500adca30f5d7ecedda74a7eaa6ae7d76260d761a06bcbb13606bb7dd7e328df823ff1ace157ddb28fecbf6b52f66cbbbf0886f892145ec56d2d8173549a9e38addbe1d3c4165b338ba01f9462c6c04b393275e755720a9f31e3d5c8e734e0e0f2375c0788ba8f86ef000fc57de4f253a156045f580a28f1d4f92dc685ce132267c089d3eef7d75a5e74be687b725c482a1ffc4ea5ad4758ecdeb6e54d3069840ca332f0906fb4472c0463d2e715d3961d1bf45a9f650f2eefee86e36a5e17e2b5d6131eb8f578297fe74ccb9b0f43a3a141419af0497eaa7756d07f2e0aa7019222a901443d4e0d14482d2994b3400f864c3de4b31e8acaefbf050fcfba7fe900c9ef4da1533f9d25c41e5ff53ae2b8e512efe0f44ceddf647b44bf3781e19285f631be3f2e09c1a44786512c5406838d19463cb4ce16f503fde7249ed752f74bbba9c3a7d26e1c36ffd6d7657bae7a71c95deb90ce4b21672dc7906fad482628c80b10f55500181149aeadad40c20a680b0d21b3507739d0f63ca9ff0d7e139de164743d5b04d7202a903595c1b6f6d0961813709be545965d31703a8276aab6c82351bcc4f41c028b967c0d82ce639882dd7d359f81ec97e8fbd6afff75dfefa44536eba8e9fbf8f34ed9cb77ac795c76e0cc5ba6dd31738c102beefaae66f5d7b233a778136b07ab0faa234f804de87c80d6a190a8de178c57bd35fefd2b567fb77ef59fe4fb96be21663d2bc487552f1dfae21affececd6fdbf9696da67d7be75ee6b122efd7efe9b3ffd4d3d5f8b350e1ab014baa2815e7b8f1023eebe679fabef950aa9b1ed91071d248203442b00d37390ada0f02c8d2bc380efdebbf9dbe12b0b3f2607d1f7a6f44d9be01f711c99f8cc9269e3d5937a8001d69fc37edfcd847aa0458471f98ae4dcd537dcd173a5102debda7c35daaf03e115e4537545b6da01a1d25c246fc2a38ee03b4c4b36960e3e26617b704328593a69255b2be04923ae28f183329ff47eadfdc37d84f8e8d1972f9d834a0b9ac8eb497e208fe45954fd49410a5955f701c42230290c4ad6a885e751831d05b4070285a23d9c37158cefc7c52fccfe6a956c91aee97bdebefc292176c8ea76ed3195688fbc84ed51093c1cc59bbb6798ade2bd90d622217fb63db8d8fc60ed3fdd4f6c5ef3e9c97fa5d4a49dbd502a882f9e89ccff0e0a9cd6f8eaa128b4a70d83a91e5ba3e83de358faba9e514b44926b2baf81e858311558b9429cd6f6922f77f4832a45ce9b87fa165eb01257e103bd760ad795a25e3cae8f6ca50aeac9ece84a1c65491e8237d453627d29d62e6215b854c16b54bc7bb14a72aae8a54a72aa88cf4ec467c3e2fa89d5d2025ad17ae12be51709f1e686270ebe51b6f3037346ce2e8ac8b9e7e0a73b7e3c480e869bab076c58acdaa5eadf0a6e4001da0614feac8745b10e1dbb6e06208ec05cfb92097ffba709d7de03280756ddbf6b26af918ae5b571138ea890bed3177323efcdc75ac75a646fac830bbcfe44c08f63fc0c7ffeb6c3fbef223d9a5b3bed729c7ff426551c4750d14eed393269c5bbc287072a788b8cf62dd2b1e5e655bc0f14c7014f58499ffe7d871f7b491fb4ebf0bd0777fc5c7d57da7813a6a23d52fea16008213bff2c72ff925ea682730151d9ebec24156a8b76734ed83d8e5f5e41ce77406015e47a6d8e5790072bbc893edf512171c57491b5e29ded7ca02bbe15bda16645f6fcf6339f2b7385786bfcc4111f97a8efae5fae60dda90a560f57b00a9be76c808221795af77f89e15a58c6be471effbb1f228be22700ee61e26b6f033c9ed191cf3ff9eecdad5e92bfaf7c6df1fb6357c5b507af201fca7644f0d891b7d41e3d59857ab0e29df09ec069ed4bd11b69ce634d54bc9bf4279bf2ccf9edda6eefc5bd4f56df9dfabc825caed3fa2b980205ede0e867078a5dcb33cdd330f8935f5bcb034165af660c16aef3b0107d469e72ee215223b678a6658f027fc2ccd7a125551fbc0af86342e5ccacc256762e62f91482ca053e4587a4541a6d6cbb7685e7029f08fc38b5c587f3b25908284621bd97f8c857c758c9bbdc785c8c02de127cfe5344a7ebda43aa57fdf49010730ffee0d5674608f1d26b0f2e7ef93269e1dffecd8495be28948bf2fa6b553bd42d037c4ac1da0e0ad6c092aac1d9c8351898dac53f9fe1f7e2f9bd418f2c34ac65d43eac60fd5f81e37d759840f52239fe5e07fab57b01d64a011db6f79f53df15e2e891f9136eb8d75f5348e9d4c55f7329d66b0eaa1dc6b1131f113214c5c8b2ca659b4fd2a98213a9bd11e21b05e929a658327047870c95a7477510b85fa72d5fed5c055c992fc4e79ee22e7f8de2d78f7e6cf37e9a108be67ef5fa8fa8a9afef04482191a781a37d1aa058745d485841da64d1f7ac73da0cea70de9df2bd8f38671e74b6881d9d9c8b42d3b1e0e31c3a5a194fafc2f7f1b5b97cc8277d5f31a337d1514ba8a728f993edaae885891eda8fe8e582fe14e073751697a24ffcba3abb302aef359f6e707e5821c48b550ffcb9245d2a8715eb6ac8732005a23dd72715acc1dfaba050c820d21e478d096b272aa8c7057918b094ebd55a8668c0f869d817b033e00e0aeaac23aa8378501a53537f2a5e280dd5eccffb1c32509a90a1f9a1933a7410b1dd8c6321f362033f03f34abe3312ed31cac04709926fcac2541ef68e783e1ff4c6e95099c2298d38368f297a537436a2c2295b7494f6008b417f94c1efd7ce57fe32fbdbaf3ffdedd402b417daa9fe74b40fc9f32405699ed05986b4f3023c11ed6127dd4c746b29103a4190425758fd4f9113dae1b79db8f4646971877e4c39cdb764f5561f83ccad3d44bade72444de4a59a3a6da14158e22d1708a72d1d0e545b7bc8e1a6fe32574f402a0db2d8dceac3194d69b56cab8f4af0f94f75fffaba355f2d3c4488c7cfbdf685623991cccd7d7fc9824765a72c6e58418a81424d3ac6bb54c1aabb14acbe13385c77da4db6ea6b4028e06a0a052c017c02f43010abe1f2eb9013063029a2daf780c3c2aebd1838dd079c16316b2f10a2a0ed0dd34e91aabced2e9d479fd943f85b9990a2588c762a403b299cd26c8bf5d25c66f4f7587f291c29b5dab51f450760995bd3e8ad5432d8d634d87c92fa4bec8aad3dc2a0ab4fb653176d4553bba4eaeb6fe544f2f98af28af9ea89687d8b7fd5af003c44c13aaa7f414cd91b0262b4058f0a4644f71a3afc85412baff163eef78a11bba8d04dbac16f3fc261c8e8ad31a0584b316a32743d90c22bd9963763f4d63cd180859ca0143d1a07a400686b13c1e8d9b7fe498fff268171f6c56e919c27ce1362cef3efdff71d26ea7ad4d3d462c2a7b58d2a84a6aa10d9a87a48c1f5eb815f69deaf17cd2959833c1aac5135c0c368c0c447fda4712890465230a45848a1484fe5a78796bd54f5ac10fbfce3b0bdd6499fa3fdaa2e6306a4c5b547265a89b62aa20d50686b96a9d8fa24836ddd53c8fa6f2a19b2a037956d8544e9bac58cfe18b615901bd80a485d597a6562713cbfa9a569b9ed657bbe7fc88b9f3c2b3de5baa535abeab047563d0cd17a0a6da15d2944aeeb419024423b3548ef495d24191161b9b6551aaf1b83ce15a193fc92fc409a6d2cdd8d5c35a4c76e629a2d4f839c03fb912c5aa4d9c6a5039b69b66196661b36d3f2d64efaf932ff70fca965e3d3c6ca37adebf8f3573450ea6940d01a024df0a8abd83055c12a0a59214d713df0f5879b90ee5f3fd5bc7f436f86e7307812fbbb0556810ed57dd040f763d5e3aebbb4ffbfa582a9776b8e7f6fe766a5259afdc5d312cb81e7436ccb95787aae968308e823a4005ca703e3fe58fab6c28706d281cb0dbec067bb833a1fbe0b146d0869bbdac041a84aa73b3eaba0aef340faa3bec2b1df9d0bc4c0acc238fecb59faf9641d3252fc146939758def41ba6edcb830db03df2fca4c7ab1f476fa7e9dae6bd0a3f68ea55bd3f460a6897b7735cef5eb7d3e796d6a8b2fa8ce008bb1e4a9515d904eb2a0c5719277521464d0604d442b0c82f0f4c8e3d031fc6bcddf35ce3c94ba6b193fe4811f117bff8c8b5e7d64baff9e77bc54df93d1eda1d3994d794936efc4cd336e14f7d8bce331f9e3e9ba113e8f9969f881798cc61de7b79fa8f7e5b86763efdb7726b9869c521a2fc9b75e83a690ac6342addc9a7d6d250512a86c0ce377dfba395e74e830387e2059ea006880f0fa02aa2760f5058109c533078c541f141356f727cfef36263ec9a7c2531b07344a8bf4fd6ecf9ff5e43ed21c58347be44a6c62a605188aa31a03aa1a79ed7aa2a6099e4fe870f54901e809bd8a419ae05f37a1ceaf47a8a0fadfe6dfabc047f595ec3e067568410ec486417573fcc5cbaf3bcfb8d15f1cf676693ccf5f9b89b52fda27ccea5492d5ad509d4a38902f6fe2ac9e461431454f8abf0c6b0d49ea2852af6931371ded4c8a22850f3082b48b293c693de08a63789bbaf655fefdde55e2b7f6a78844f5408a8f7c9851b13aa688c9af6950c51946667b20d02047876bb6ab45b1daeaa2787b7ba601b7e6c59f5e9f374fc26f56f72279a42c2b3d81d3c44da150a648f4446e59fcd68be0fd18a4ac210a491d6de281fbb962e17cc9f1f8e5ea8aaad5bdfc7071f527b366c5b547a0ee83d53159e61dddbe5a51139e989e94dbb0412f502705455ec4e9b3f9d1c26fbbbf763ea62d3686d4f24b8ae418f3772dcfb4d6e10286857125af50dfda8be8aec9485481dc2c1e6fe71718252ba0eac90af43c4b819e6d42619e83f440a890d028d86b6e811ef1396fc38cf113270a31fbf877ee5bd84a7d17290ef238aa6169d1c4bd810aa492790228bca2095e4ff83c764c96de5589210ddcc0dfe9f923ccf76885516b426d19ca813ee5ddbbe67ffbad10cbe67cdb7f841f3bf5156c6efc00b158b6dc728e595aaec2614971cfa1b91e4e446f633fd4c02d1367eadea9e7b569a3be4b2b0458647a80918536c5bc2f6ee75bfdfba139c76d481f13e5372f74acb07a3e310fc422b731c38559baac3dc8b22d33e9698f9a8f83a485858c5ff4db8693d7ac5a413172aa1f6069cf5aee69a2ee6b420add9247ae1507267af26878e5b43ee39e6079629cef1ca0d3b1a158ead8fbfcb59afa4beb667d776e5c7b700f2d28c7d4be24c7890d195a7c8f24f6f8ac1e362b90f602111166205b3ccad6eddb4648aeb921a4e599e43c7e3e6e0226bfb676088b34981b070f14f5fed60eda7308685c5de9adfe1e1c90061ea8c48d584226d95481ae36ddf6ec21828402f3f3c72bbc99d2729d3ae49177de244bac8782b4285d43212b4a5f24cf837b100429664c9e045314a49074ba2e06aade52c4627969d8a379f769ba34d0eb4d486b008d938478f4b4d13fbe2d07ecfa49bf0d9ee26725d92b6f9b54fc71e73c84d5733c04600be930cb90f032411e48583d9778e24cc94acb6b8d2c1e3dd0a8e29c2c35b2d0b006a5150d0d2c175052eed465e73dfdad3482a13dc67fbe0e9d8641c394db60a88f4df42ce4423b20b09046131e35574c89f945bf554d5877f6af385f424fd4344193e7408a84e4c8a228eaaf33ef6f2479a22f8242a076d58ac2b340b2f9c3a0430ae668461f38c9b9fffec661f507afe811d71edcd0d8dc0af2dcc4864ba0e23de0a958765848ee5146e9b53c2c7d581bf240489e690d9a1407f7a4499ee90b8405b75e5b69115d33481f701ea0fcb0434e3a6ec2b97bc87f5738ab3233857dcf9d5c76a21e2fd0b355260b56c949db8dd3b907abe85c05cb26706c93396f61e35e7ed6c2ebb5139c7ba5a25853b96adadab5ea4575c83aa9c5a238ad7150e19486489bd3163fe5b943d1e858f07d0ad2e21759527a7334b2d468f16b1120069cce3ec9657036e05fcce7f9ae9d7a80d2807e1cb04401bf7ec7bffcad11d6d5fdb2c3a71d84d8e7b8c3efcabf4cfeedd250a7367efe4816ab7fe09b5a52e52df672726c9b5a9600cf0b6c0a5860d06fee76f8d883ab7a870d4fafbc4d88f7663eb73682cfab43be7ca0f21e8b8df5d82a425bcc686f5f727abe73e4822eb27ddbfdbbd3cea37a097b21a43e6f05fcd09e56a556b9cd427ba8e7790539eddc908176d015d3ba1d157d5e31ad0be92cbbf71638d166f9a17cd1cc19cf08b160d6cc65df9282a0fa0e181cba10f01186935c53012065b3513d0d2dd6421ef54990e4334544d317fd5d7d89f608a9c053ef8e0c34deb2ee33eee4ef7bc97e6ad1bef585c7a688c09e619b5d411edc234be185963dc93293f41f3fb29bd307bf2b5a7f37e8a35b8598fbce87d316832352e4d46f753008abd15f3c54e861bc9b41b9a6ae6da5406871724fe9f2b71e78cbd9f2839c9cd0b8a802b16d12480386d236835b3a44f1b84a5957dd67d99e9ab2765ca4411653168f9e880ac1353d17c5970c9ad7fe95ff13e2a3092f8dfa18e74250c1590ded0d457bfa509614ad29208b4757e2526c185b3be8024178149425d1882c13bd391adb3d534ff87b98bfebc29f08201d3073387b9ed1a14c144d2793d151538d767dfd45bb953316bfe65b767b5f7668ffd52709d17e8f1d861cefe7e387d90467a9bc75b01d7ee02853db76f8b64d2d9bb91dbe83c2aeeaeaf52d562c970ae487e7a645162b0a75df0292278681568bf45d4a57a5100e296c5f027becddbbb6f34b42b4ddb7d39051a384bd827c100c22da7d58ef50d0ec0af202751f7032b0ca40cf5a60cbe805779735f9c5a69fbf1dfbd305f3a4dcce9bf4d1c35f53c1206513a2be406f39429e33853e69cd83da1385806400e982b512e024771b7b2d06545f168bd933e87cafa0ef711e15397d5a584e90691b5a743fdaef477d9e0dda61732bc8c35a91b8784e29024adfcd0a9ce3a3e8c50ce22cbcd7a417dc44d5e07759ea82ca0fff2ac4d76f7df436350b9f5f743628221c3a6d9d0a0da97f9aad40b655165638f64f5adb48ba4920154a59b2a244735dcd58cc59c5c85de52807b22858164cdde29aa3d75c22c4b4871f7bcbafe7f02fbd884816197920b4c6408be6e469b0dfe93e1e3bd6a122a48936248b099367c15cfac0efd90ce7210097d12d372159da74704dc33380d7c5f8fef79fdd892f1f2aff7d7c5ddfa5be27966c53cb5c0a15e842c0701426cbb6b3255b503f0fd55fc343911edea7e8f5f0d692ead1138c6342bdd60148975e740cc7c1bb301d06f93743529303a1d36685fa026b3d14922a33e9c58d0b93be48ba6668f28b71d0ea9ef48cf6b3e229c4c903c90785b6204fdab3cd35ef377b260e92a7bbb957c444ada12ff9bed02b298f76f85c240855631eb085d4692d231892cac53b18aee8f135bfc0a23b5bcb08acbdd8d76815fd224d4f5fa46a78d2876d6b297d8539a524bf6f350542052894474c79f352e4bd3bbd9ce8df939dc5ede20c73cf52394b8ba6634d3c703634559e0e5795cad6b3b86395a2517c8937eff16972e25fbf68cda4aa4ac57f3d424cb554e0870af06a58b0d5773148d951b4484d8b8d503cf5a729a8d71860d97917019207d105902cb530a0cb60449817ffbb6b3eaf0716cebdd0037b2520425f742e4623141c15def90ab0667155e76ae989ad2a5de2de7f94d067c77b4549ce9a469a76ac421d490e5a0ee80c76aaec653b088c34cf9e97f2d215df8401ce2ab2a9027ba47719358fae4d1965e27a80bdc1ee73d97d7280363cd470b2d34b24ad20977267ec5890ac023969057970a706b46b62fab18a77b33d38bf342e3a2edc714c4f928b0820970fc1f0b889dac06d1e46c4f2fb265e640805e803fa4719a75e9e569053123f4f6067047d563cab201f9bb8825cca6d58dda777c2207c24f09ef1f4f5ce0df68a77cfa017ebbfb1c013d2f388df06efdfdaf3823ceb826e9267ccc35c2168c36994f9bb3eea99dd1fbb526d7fd8cc8b0a090952a8ec26e16f25b2abff7b741130e20f462ffad95e3e0a078b142eba392aa073bed2b4e402ca8ea3ca5c132717712e2626e0ce19848bf651fc1e78404345b44ede2973682253dcbe2efa357c29c45723de7978c6e312bf434e122898d28be6fb28588b02bf1a1432d5a06ea0166b05b5d892a10eae7d7da982e4c934c2a2270bdfc3de571e751cc1ad7d61c7006d29128e89b211bf372284a73d3128c014d91eef3dfdec35af458438fde74befbdbcc23fa33c25bf4b6eb41fa84c49f56bb6c29dbb3d65410f55ed2fe540e190030772e015432e862adc29d6fda5f022e08f79d1ad109df355c1a8fcab7a2fdeee105e1bd7aa249fae890b6ca9217663bf634d443488d87591f748f4ef3b6322c65e6be20c2d97eabb2e253916bfa9ef56fcc8bfce51cf9147a670c7a5ad3620c748531673411f49266229e8b94e91fa4e25c79abe8bb3f6e7821ebe558ec184fc0a143eb6ba307dd73d4e1062d74bf72aef200d9ce5f77cfb455577d61ea87bc22e6431886c426d406e2b39a6f7cd0dfee9c4832e78cdaf407746a71c70a05fd0eb7aeffabfcbf688a64ac87e32e5aa58b527e1e20c87fc2ff5f524c7b1f98bf029c013cb7136e84f017d57d19372ace89f81fe8bd19b6bd03b23f1b8107ff3909a234ed3fd93095802480a06862aef179aaf05222cba3d6d06c0363f0f44c469deb170c5b2a1798b74baacc269ef201796422ef091c0b3f55e400acf87459acbf6aacad678747a96ffa5e7e8efb9f1f47fedb672da6772c25f74c797237eb85ff14c15ca3aa68b186fcd5e8058f4d685529fe13ef2342886fea5828d0fa02d4824a96d86e31f6e8286db96d748405701f2841ae18951c5af6e976b8498f3eb075d7f3e56880d67ac5df6fa7971fd45fde07966bb77d338c901f6c0d22e3ff50b79a8745f6ec2fbfa883ec02107823c1af433f017bcc302df7b46f39ac5e995e8572fcba03fd622b7aec836f0b1b07c21c71ef60c8bb597498fe8d3f372ba37e9b93a7462d2d7e30296accbda83f38b3de6c4c5ce9329f385e83724ffbd41d8132d440a97422358f3d36b63fbe1f7fdd8fd488736427f22410865332f8719043aed2022c47efbf5abbfc0f728677a0fb77ac5680f53ceca30ffd0bc40ede19af3846c37a3ffa43c8e8c7f2e209f14d21dcbe8537fba5abe397df2145de33eceefad62a2ad3dc803e3f2abfb6593afeda040c46c585c2ccd36560fc2f2dc9b9966eb253b588a0e1c9a0c8f24162a08c73ff7cbbb2bdd05c85ad0f9efac325617449d66c23a5639ab3d0dbea641ae3d8f05bbe2f7714514d02181b002b4670e2fe88a4ffb5d3f60cdd84f55411d09ba1bfd238fdd4ed685848a7a2c8d32ac9e4b9a4649fdae9e2f6331e6403e3ef053bd82649fdffc3c7849af87b8d7a06f4b0f1f8aefb6542027af20a7e741af88d18ba5931af4e32ade4dfa9c5faa7f60e9a93b75c97cd6df72a8e3f93b465adfa15ec00bd5fcfa9728bcd1fcdd61e9a4d6f451829b7a45189db8b5ad434eef3fbba5e43f756c8b4e237a8860ba78b0504f8d467b9900eb3f536ead72ccd2ade32ade4dfa96ba1d2f58706bf23bd17b8a9a832be6c0e68861b185aeede181f4828665057b818ee58584b6bce9e62ec2e24cf4d8161a1880ae39d1fdd276c5dbcbc9632005427bc990e2a0ad1cb0c543fd97e6ef7a4de36d130616f5d804fdbbbb5c05744c3bdbc4797d80fffd3f9cbee8b8599f8ae0222057fc083d26ad4f089e10a770deef3ce9829ff818d68be9cf27fdee70d23be22eef21d0a78998f837e5b60c316b4b057260f1365905b9cbe859166f1354bc47e2e9f1c5775e601b9a97529f7e921027de7be1a167232d579f7487d0b43ef12e8541dc1782c2e05b68f045dd8d1e07f43c5350ba504efe7eeccde79e77d93af9ef13c45ed1ad3ef8e2b82d2943f7a7c2931944d47f71725c6ed0b757bc9bf4f9e23b37b439bf504ce2a9a00762bb9abfdb6eb26bbb7820818a5cd37388b96670d99bb64485ad32996bf05821a18bbfe732fa517cf9bc85cf2d43e8494f90b46502dfca810af5f862382b64f2980209584cbff7cb05249165f528f195c0533f1b7ffcfcf1f29e8cc6aefe76dc3605109714e102373d078ba5ac71a6f8a581c02df1723c1706a60660913778e31bc07e79592a8425023b2bb0013f142b4a16851ad8932d59057911a367d983ab193b35103daea822f1f4773c6af71f4f919e65dfc543f20ec0669cd1839a7cf81e60aa89936209912221cf85425e3491a937050b356d17dd5fcc70f270a4e733eac007661d7cb010690569a3afec23e22315bc3d4cb9e35951aec5a3b4f45f6cab1379473cfd8ddd934cd3e70616e317868637513c656baead776d170f44efe1138e429b02a09013dfacacb995c9969089c059dc7c0faec69bbd5b7c05f1fdd3734e58892c283d3162c2d4bb5a12fcd2c4f9d60a81fa8d306079a296f91d5f1105680156437c5723148b5fb752fb53f50dbea7d698dd78d81a7f5750ee39c4fadd05ee014f3cc0936c6aa92d7dcae2b2a73d2a3e0ac4819bd002492f3e1127d8db2ddbc0b9428dc9bf527c94aecbf7648b7920263dcb1e5ccdd8a9c1507cc2b6075758bced4fcc87bc31a0cdb5d70871d075c74eec8e02e1d49b14d46772bf6f42522ce499e8901729148b22e1e9d581bdc8f09cde2c503e575875eb65592542b47ba6f30f53fcaccf63c4f4285fb69051305dd754a4cdad202fd2b849cfee512696e3a0a7e202cf6d8a5f31d1c3fe0adbf2da3e1e08d22f93e6b9bbf87bb28e4de849789690492c5d4fbd47d33fda2bf72deb864bea3b9342f09885ad435254214e959c5fb1fbc85227c5e1e2db23806ee2a6f9dd5f2a9fc71a8ad347c4faed748ed7d3af8309780eb1d000ad45259ee02c13a8280ab8f20ab7af9945f07eb204bfd8f80fb75ff03fe2d7325cc507b314f96ec17ca20fac65f01046127a963db8ec215e1682c94d1a8289e22963530677b857887edf0e6db8335d88c38e3ffee21e384fa6052af65bdc02d84241522cdc43d16b26965d6203e305502b0e0a8d49055238fdb653bb0f979ed28bbb757bcd4f9f2f715ee8f65882f6e0f34dd06041fb24f128f95a46cc03e11e0e4649807e62390e1a5ce67cc63d4aa2f764f343585beeda3e6b2054afe1467fe09e83d08b8ee676eef68e350752929089ece832e0864617478a2ba396947ff00ba61ada6327b0691b5b14a73a09bd5680e779e8475f11f1c7bc26333ca24020ff5f2a5eef79ef86680125b7b88a580c3f18630e834ac209d4baddf5d0666ebe79803877633f3bc9751fe847a2305948b6b99e74b26dec9bb9fb305fe3b32a561a07c9f6e002fdd0b8d4dace4384e89b7afaa78f7c23c4e9fb5f5a7b1a0e386b3950c116043f30210f79e93513be2bf20d0cb24d2f7d7849f7478e3ffd7ea93886765b3de323f9630731b47bf720bf812404dd1ecc80b184f612242118f4899e97dc2032e927db43adb97b703de5fd7784b0c46cc46e5d8be7e069975f291addf0dc42b2c41a6d8b60aeae80a7b44ad3427064574b8ba6c5b256ed298b444f88982075488a2c6eaa70e0277a8581d3d0734d7a7ff8cb5520a03872e37e6f2316f81e5bc0e222055014908348146fee04ca43037ccd8c5b7224079f6b7f708b5c5e778fb2b0546b240bc942ed7af65838a48b293e6e79ea106f20a461d00f78eaf68a77e0dc830a846014bfe83731dcd9ada59cb8773f36bbf2ea3a21463c7ddf19e3e70b31e0f1821b7ae3fc9a561f29d812e9eea460d20628988a50570a4261742e4b886d43eee317ed7e5fd121bf0971d90d250f3df78b1caf43db9c35e942c9dfd3de24bfc2dcc66f6ca2e7910bd902f1380f19053ccaa6fbaf191ea5a2675df3e3f4d5f35e207984fa93e80b54696dcb6bfb78202a5f3f567199118f7bb133aefb00372a30636743377d16b7ceaba74ae7a19e12dbe1fcec691d3a8be219237617eddb8357d4435045b6560c54794b59497dd8fd432d1f1f69a261fe08d712cbef6140f9fd5d17ec7370caf3521fefe13c919515df7f7ac700d55fc351491d93032f1ea709d38b9d05ad26d0b1ac527832f081e8df91141aa333d959c5fbeebadc6dcb5c2f0bb277696237e5aaa7ae43523b2178da13a309c5f8ee0467a687d5f38cdeddd859a127ab700e9bf4b5c2e615d3818a778df39d1acc7626fac18af728def2f836030e5b2f44af2f8e7aa4f4092146653df8c1d37f15e282c231df5c8b1d0c5a2d0244a1664b759abd68f18282a937034a0fe592631e1d7c459510ff77cce383a7bd2e445bd1f1a419df49f95a1b7a75503a0cc23c11dc59a299fcea0aef9ee6fce2d17c633933ddd67f7afea13539a2ef592bde13f69f2832e905e49855bc6f9f6bfb1412aa7aeb5801190aa3b4c657781f35e0e20ab2f20d3c5b77101540914b4f03361ff7111eddf2305921e1de8d879eb72f16d129e64f15d9fa9acbfefe6192fbff53ae8f92fc5db6cb311f9ebd60af1ad99eb78bf7a37503e4f9c50adc14de2d20076a20c6e440e1b142420ff7990a07f77ba4905841a9c70b4aefa3ad25b7cce5fd038584b1d0922957f9baf06f7814c60a66738de79215d6c60ad1a8107338701a0fae41cfd516aa493f9fb5ab6bf21b37be5cf69ccbbed3e097eee3fd96766acb8cc373a4437a5fc70f0b7174733a7aa00d60abe3156c814d4a29d4e5af9d844e4be97d81bf13c4a54e873ce999786748fea6249c0f5ca33decfcf2f6a6423d935eaede5ac76cdf228b673256f727d133e42ec0afc7f865fd17777e0876d260723c562b14f5fc96358b9a796d8f10962d3d91af69c416456d2e3834344fc76378ac90109689b650c9d20dc7d3ef94beeb817b3ea11875c280b4a8075c7b1254e95966fe5ddfff9f76d9b6a40803ba42b4df6187b17bfb039ec79a7956dc1ccba26233172d3d1e6ba6b52d1e6a60a101f142f242c28dba10f7b7adc169cf21183a0d83cfe6b5838ee983fe1c331925c1e22dd133e87bb62484728d1bf43c5bfaab3d4b8cd3a7f18bd413215ab75690140779202d61886905223d11ef786f98e38af8f4e508e8e536c92f0ff959d6209286b878fbdab305c3c00d7a4d842813d3e7fd972cc455a45722b7830ad93e1e881bfd87250b443758ac9030acfede74fa5cb0e159c7d2eea5ec2c6e1e836fdbaae3cabdf602b32c2f9da71386b03500df84cf766de9ad1bb6db1566d055c0ffbe56dddaec99fbb631108d81ad073a7990c9d6b6bc246b5b34307921a1251dd87b5e3cb7e91f1ebcbc87bc1e06dfc16cb3281ea748c07792c55b7b3b28fad981f160d24b9a7cc2e88739ceb28c38bfc9ea5402fc0bd7512d215add06c8d64674d616d646a2d95b03bdf7fd7115e731c1c30964b599fc06179b13f2ebf15dbeedf38da297acff8259a389f90d26fbf0fe2b37e8d9d2dad11ee284ff922c2c315bf0ad44127b0e7393669944f1b8504018f7299c2fbec7f61c220f84776c146f7d7bdb3b7aac10a2dbf13d1677c1eeb3fa842f2a80a274c33f3168cb5b4fa258fe70575881f86da1b3ae3ee0deb4542152f35bcc39cd4f948d0d94849e43dc11af9128e495d83afb2760d1d144685a746582ced00fe3a98496a73875cb16128a7bbdfb0cbeb9e5e96a45926ff24d7c5a166f93b5c31cdb963c4d7b7e49b72bdff48a69d7a0a7e983de3b6af342ffd28be9dcf3600ac42f54f4da791da2060ad10b7a50890dcb66f29bd4830ad4d524e93f9b47c9f9e51e6539a3c7e538d7a4a7e917690f15e5cfdbf2da3e8be8aa5a80bbf8bcc17ab22c137b564544ddc77096bd2326eb89c7051ddeb10acf15f57e7efac1ff1a784efffe8ae71014813e9c9e200e8cb21d56af3d8e306b048eff512ebee9605801ff7b4fb8f0825f8ff1dbe53491bec3ecf889c98bdec5157fdc11afca82b285063c6671c506ba69d1f56c5e41a9b4d80ed8a46fb75df7a92096e6db9eb64c3b21440c3e83d966a621656b876cdb963c8c3e4fd74d56b0b98915d3090c41d007bd7e5e3f9297409a2f656561f13cbe2051d26deb8fa3380f246cb60fe797cb41805fa33db43c153143d5ea5126996f2ca1b200bfd6746e4e1ff492ecc1e59df85f12c212b3bd68e0c76ad9101e3be33ae1c014b68a595bc884151226e85885a363bb84ba5d3be016a93486a64ed7854fb0a1f45e40d8be3d85e5a9071409ad89b80cfec12e87efc61a075b17b7f5860d4b608186032ebd61917bf602af307b2eac9eb3841ae65ad6cc825b4e6ce140224a0923cc320ca62dbbc04d791501790d839ed90e82d19fccb6e4b1574c1bf4032118cfe4d70b564ce71af42c15d3090cc172e08a5e85d06748a691e2a050d5cd26d40587124a0fe43d78205c514536915fdede241711835f8bfc26283f30e9894df328adfdd75c8f72bb5cdb672b13da4a2412fd816b72c287b2421f36303d9bcb99bc90d005ce2d26435052af4bdb31234388a37ae6ffb92fb671d78ae358c0330161d3eaad1a6837525220150ce2f73f8c271206c422ba5e03920a73f8f9b7add8ffeff2df4353960dd941042d509b0270931494da423bb64a6fbe66669383bf78a76e5a2358affbc04f389ecf80651bdb4287cb6b79423eada138d0679b516e6cc5b4675b1b48bab6a1432606fda46b91d77ad7fb7b6039439defd26090a552a8ea2606e31488785e4cf67fd7f4b807b599fc7ac93ca864060cef3fbb47e919f4994769edbf66eec1e50ddac2e9e9cdbab68f07a24258c1c530d352a0dd4bf9c0d96897532f629207825874924577746cf76107655d7081101dffbe53e7b66dd52704368fc3feaebaa2f64605b52281cdeb44d0062ef0dffbda485801adf890beec2b9094c753d7fa0aa4c3fd3bfde94eff00a172f1564affe4ed99c022e7169dc23736db2e5921214da052856c424b582fef3e5a03b1868ca278cc80015f8158b82d04a3cb504dfa939379668943880185cdd706ac21183e719af4ad15ef9007c775a6fb85827be51c7af8ae38ab9bc64b2205b2c794fd3a75fa428ea10f4207ec382e48cfea416d24bf493d289bfcdafacfee51961bf439bf36cf3ad91e5cda10f8ef590351b94bb6c5256aa0a17ab3bda6356f304bc1f024122c62366bb1953a36a543daec2e63853876af734f2b54c10aad38d2b02d5fea01e6ef7c9b6bbec74f4071b8e2f779b9806105f44141526e46f4bab7d5e9fe00bfde79e2e8a3134c1cc916592d9b5a5a074a320b976fbe19b618145b7a2b45a4f1c6f19dcbf85696a6cbf6760bc4c293acedf1104cbe99c5d6ec8a69aeb0051b5fd6104cd3e9a4d6f45ad65fbdcf3ff9a2331f9672d323b4418f17185cbe61e6b4748ef3d73e8ebdef9c23fe7970947e91734c7c7b04264ec3b0b4f21b0c1945e2bf7b63f70cb3f65f528fd2c2afcdb34ee651825fe97ffc776c65e2dd2d7a4721af4c1ecb2a88e94cf4b0ae4c0e1b38cede8eab10557fb79d113d5c552a4baa668568cfc0da48763c2e5008d6e9cb9dc5e07b8438e1a00b773c1ddbb7b73819f0604054d2ea5d4829c445a12d0c140747e1d2d2885e6cef96b8cdb6d94567d993a7419e07f80d2d938ae3ddfbfaf5bf588856b9e9a73cf08c4854d14bfd659c711fa8e81d8afafd7c76c6fd4876a6bd3ecb5bf75786f13e8f9d40e9e9c56b920385931c3cea6d4e0b052e6f847819fc848defa509295f2bb8c467f1f38ae9226b653ed157f42e853cdb2aa67bea1d194cfac18a7793be67a9c84e5ef19e983e3bebbee3f53b7e70e435429c7ffd9dad1f1821c4d9ab8b6eb9f45121fe9c5efcd5e819425cf8e2bd839fec2044db833b9d3a647682f618da7485b7955fcf6c0fcd6fccb04c5c419e6c070cd67f62b296df9e06fdd8f8189b905f9b7c8c35e7c9d859ee6cfe7ac74355cdb6bc52b60e591efb8fdfcb66bfa5b9ddcf962eac13728ecd2c88d650288f24476c88c230f074f10b7045ab549ff0abf032e039f821ac70799f898f067ea6889ee2e15c2556e1ef61d051efadc47bc3f2cd8a8ec233804744beff5dedfb76e9d6e74a213ae7ee5a5f394988851f7dbe68d10cf58a86110ad2aeb41edeadcf032907a423631f071e018ee771d8e6b6bbf07e0795c2b4581e2a54d04f1638bfef98ab0f962dd7f6b78ec7bc395dfe385a8c4af763da6384f2cb72d05ea3142e9522b5e7e2283e1a7bf5e4002f134abdf652fd4167d3cbbbd4dbc33803ba549f5c3e0acf293c47e192bec2d31d17f8283cb7187801de1fc5ab0fdd307ac50a213efef8d59ff1d9faa8e2da5a138f6e06e9e37d156c64e7a0f857f7f483a674ea24db65c74eb346668ba0bc66002fc3f7f712fb01ef85efcd029f6183ef0cf05d06bc12f488fe2425cf12df318a4fd5f2aae88d52b8ec0793fe18d0cb51f4a55fb418f76502a7e7e800d47483df9c00bff0cbf57822fa99c077c4771ae32bf5bdd4b6edf712a275a4ddcabd4e95704d7af77dae95b256975ad9b95f13ed3117e335037c4614bdc0f81d13e0b757427e2b402f205f49e6034bffc9bf621e73480ecf30f8b5cd37acff02f3e228d02bd6e36314be338aaf98b770e70f3e1062c1ac590f2c562d163b829bc97775b582fae454da5d3c817c1b5784ffb03d3c90a1d87a90a5d906b22b82a10dee1a96e3b9309e4b1cda2057317022a1356b83870ccc90045cccdd4ee879cac5efca7efce4eca3fb623b6b7e1e8276d1fb2ba8b7af2605cbd748a8d23b0218165be772f13e87bd3fcfe4cf57fc5ddbef3dc6df9b28fdb58e6fded53bda5e22e53d114cff8c850c9565172cf4324353d93c446973e193ac6d45588832991c3c4f6b0a5be6f2b2843a562cd9f6dc96906c732ba603a18c9eec402916e24a5a316d5bbc4d16e22a67f42c8bd9942ce0250b716d6c7b3437e4d75c7e75882b69ba6ef3f82ddaec1025e79f3c26d7e097876ab7cbb53d16d1c77b9fd5bd99a083b9c0bb1b5d48e8e23e72595ddca7f06c1d7337cee26e6e0c9ec71c433d53f6e9226de78ce3bb0d3af21ef5695a81603150676ddd68427da00ecbca7278e8886082b459f5edcd83d60247dca60b24c963947c0e5a3cf2067fbbee218b2ffbfc057f73c4494edfa3de12cd99e89ad79e939b793265b2b5ad5c8db3b52dbe28acf0c6bf37b6a4f35e6cd7a60c49ab3c85d9227fa0308d2dae0acbe2ad6e4fd09bcb0e94d28bb901c3caa4dfdcb468c29b5b31cde421704055330d8ba4ed212c868b7db1b9697e2301c5b479fc52d2446ceda579fc0a937ee0802a7b01289eff2fd98db7f1096f8775eb445c077b346144f1e0a2289b5002f504cc73b0580a34619162b26655d82c66b61856fdcafa57e7ba427cfaeb1b67bf70b6fa369dc74ef03d40f240a85e843c0fc2c903f81a907b0604052e97dd9704ea1055317b1f16f77581a4541c7f1e72c327fb4d1162cfa507b67cdf5fd4ac087903fd4a61bd379965719c5b5e490abde20a09c3f8a6c472d05c4545167e845978ccd3ad3fa2eeb9eadec2bc2249f0262e0fc71a5b2d455abc1daa0bffc2e0c79828ac3b28d82abc7b363dd107dbd3b2381eb46c153ddb1e5ce58c5e7031dbc57711ae9edff40a72b33d62f2602896048bcd090dbf00bf76c5caf92d4fc82fefbf60ba6ef3f8b5f45fb33dca27bd89629b5f5b6b0d8426b04a05e3d7407a3dd9efe5e356c8bf8543571d70801fc3c4aa8583804d1831c0a93ac61d8dc43b154e4914cf54e548f2398557a23c29ac7087ca95328147800fc28e5548e795cfed07fa613c67c64623c0f3c0970bbe4a15bee0a14fa68d8b08f1e5fac805f3a020eadf04a4d8e277807f56509f6088a9454f31f466ca72c2d6283a7b8b26fcef01b13641ed9b4c8184ce33e984ba034a7a47be70daee6d4f12e2a4ab463e71d96142a44fecf0b709fe1ac7c14e64a779d176516fcb75c64569cc546b0cb27d5db4534114afd46b10515cf6978baf527804789e8ebd2316ec8c05aefab954cb41947bd98b613ce7e0be30ee73709fc2a7ead873897a3f62fa313988e26b3bfd7cdcbc2384f86cda9b8f7ddc463158f7a882b5470222565cfb06fe8e359006f49fb748e82bebf4031f89ae81d477ba076b20fcfb33812bf9cb51f2a7e5ab92be57f99b0ee199c023c01dd6be33f59a613edaa94979d5f4757bc2bfd5edc9fb4fdb2b6183df3c46af8202ad8cdf4a920f3d4e0b412d8cbbb3d03a267d27497b503b64425e74fb307948d61ec46fa5a4a0e8d1bce25af87512f2cbfbaf02f4c2a057c9f905ee30fa167e05f1e7825e29a35fa2e8adb8675155740d64d2ac8fb6dd1ac8d6522098d8e237d98bbe4e4e643d5fea3b39574e9c2977a6dc72b8bf9d334d2861085c05f06c35409c990e2d299b1d90870e70f15ca9a06955e111e079c0b1062256811b5a2c2c8580d3a27b09f03ce0b10110c5d79df8eb159f7d26c4b41e13264ff2f320de12f7345cabde5c3b5dc1fa6b00bf55d0efa0837f1b58d1b1a310bb2ceade316589103fcc5ef8514d0d38a6897e0af08780d3444f0aa01438790ca4602a4c5cc3bf03fea4a01f52ebfcf42ebfa55d20c4397f2a3ef01cc9ef6e55fb3e3579a5fcdbcba97d4ff987bce91c71458bbfc60df0d862a65aacccc7845c02c59ca7db4f097405c363eda9ee77f17c312916a8cdc040b44ca495f85a3db08167a39f676a3988e0bfc46714fff5c455b77fb583105f8c2f5ff3d93fd49db5e8afbaab814361d420345987ddb31a707e858ea24b8a59b30ffa47a7355281ccefe88cf44bb91cf6fd3401e4e27b573b33d577e9ef75f1bd99e0bb047c67826f931eb56f362912935edc045890903e53a8b23d39fd4ae061f05f9190bec3e897307e31e169032fa6a8ccfe2b019ed7ccf6d0133d53845c1e92b5472c29210b6f013dc8fdc6f30bfa307cb46205fd08a36fe7b702fc0287e2d2e383d1cf54f47e882cdc3faa40e67e3af18faf403021ea45594c807e0867df1ffa9cd2e329f9ea7d53db0e9013999e504a9927518a0ec947d64aa5d960b109857548a5c5b219048fc645964e31d3e415014b44e198f81a3eab7f66cd0b424c3ff95f9fdcbaaf101b0a7ecb589fa9beab1e618c3a84b2ea4881c88e69f9489b6ffc0967c053856f4fbc5188aea17de6de9c26c4411dfb2fec7982103d4ee9dd77c3ab422c3ce0f31b964a8bb7eed39a17424fc4dacbbf52f604de9de15024baee64490c4ffd6b8b23529f136258f1b517f4f95a7a1abd073f7589e4ffc05bf2863f34d73f052eedecb37c3ed39c15ed4f89b64b816a778b27912ba23965daf2cd648adab10ab883fb145e499e04fa23a6384af01c5ad53291ba946dc7147f29b27df2b545aede93670ec4e5950b2eae9053e4bccf663c3c1f1e07f5572d2910f2440e347fd7d975e441ee216787d107a5777e497a6ead3b7d3c72a4889727d56e427bd0ea7b33f44451827623b98f44d14aed4147c0b7c2631e4821be7f1cbe57194236455dcae897980a35c06f6c622b01ff9906bf79568fdfe4b752e305c0897ea6413f93d14fd61ea4b8207f09e43673a3daa342d3e386cac6f25b62d00b7a50aed11e8e95dfcc787eb5e27341cfe251ae7865d15dbe02f9f6c64fbfdc760a24d572e356bc6aa755fffddb3f0bd162c7562be37ff7105384580b6f2835b8171d289e70f0772fda615e9ec245ae4713be8a090a86e7295c60f15c52a5fc6b81f7e51a389d1406e527bb279a293f7b69c583e33f1162f5c0a5ed7e3b053c66016262a7a36e756260b110832b2ffde06f525186faa4387d7c8fa34244fd8ed09e29b7f80cb59bda39922fff71d6f9452f2e6b2f3b2fad7ecd47e7caceed5abb6ab69c98aafeb5e18c6fe64bda4b1a4eae7ad727ea7cdff896042f88a57ec7a79cd9e2cbd633846895d2e6c17d0e90fae0a116bbf798247fdf3ded8ade55f23d53433bf4f0155cd851f6f60962a03fe57858dc73cae94b1d8aa9266ecf32d51f5e2f6f14dacd453ba9e9b40803b258b5a4a73d00e0346121e6ec50619deb94e339d5af61e0aeeee772c66739e353e143892ffd1dc5ea6e2d07517cd590657badf04bae1e93ffbf0bfd76392079162e703a03fe13615e11c05c5f8978ca4fb9cfbb25f66b549ea254e4305738d6689c71e057cb25e4ba58f11727e70aa7f6cdc5f3114d4f18df4fed51eed0da05b5a7490f752a7457805f4eafc2c403fc127d97f14b6301df238a40af18f404eb3f6a8f5cc66fa03dcc792081dc6e647b00af30ff1ee097e8b949f80db3792af9bcd524bf02f22cf1c4f489df89dba390705b792071b1fc5d2ed8f352ffdf6d77e95c71913f95c72c9e523c0edc1a328944a13d26a8f03ce6499026cf77a28122672ad64292844c7e7df7c7a73e94137064d65357bef28a62b01e057fb51d15a41879ed55313cf7b6337bee2fdfb4d3d2ac95637e94f416398f473d31b2204bcc509cf38833a3bd7c3e7476ca91d9274a45b0a4e55561c941ebf5e9f70c1922e19eed27f99b15b679b7dd9567cafb5aa7b7ffe02ce9f1b4fe579b7f9d2127c0d4c6160f1c3b5c3e7f7aca80033b487a5f398bba74897edf587c5f217ac1c5f715e2fd61b49fe939104eae7d01428a654d87f8b4255669099938da9388eedd2365a22dde17c6fb95f4649a9e83954f41b8b6f00b0dbe9805fafee1cf1efb9454e86bd6af7e6feda1e837788e7aede311056bb06b56dd3205297b8b3c11bf42216bc881ed3a7f293d909a8e472a0f24b036e002577b15e5a8ef6dae076db53c4b21bff9e897580846b5970ec1f0b5bd4008c6e457b72ff3a06cfc06d6326c2118e641c5220a8e41df491a51803c680f44d12b65f49bdb1ee411f39027e7b7c2baf6c2db43d1b3785071f356b3f88df3d84bc07f5e227e7f58b06848d403f9eed367ffe3ea40b42527a7b20f1e78ee81cade92c98b1a2e5fe81f2c434741f6d495a10a1fe8758d3e333250d9a94ab3f22d95c954e1cecfe2a60387eeb69cc5ed253e8bbbf2d239e203ec1e4a0ddb8833d21b309134ec8bdfbf92f3c3f893bbec7b9d9c585e3ab0c758ff88db2fbd0bfdba095e912bf9322be0fba0f29e57d2db2b8733e2f98c3be33d17f4a892351b7fa7f6cb36db13672bb3b3a1637ca25296ce92d7edabb34050290b9b932a673d9da5427c16197c0ec711af492a86359f439354bc0f44ff4ee67c2abc2ab476dc1239757fffe3d7b7fe8423a51a719a3459f3d8a54d3492cdf70c203c138f56e38c424f6f77bcc794a79ec0e90cf2817a13cf6655203751e1ed815ed315d3aeb562daa43f3640dfb2434380df9189f8f558e5bf673f233c71457673e561632bc8f32ded413b2024ab20f72cedd133d01e43f15c86c97f604705ceafd11ebaff680f35be6303e7f76641e5c9dbf0daca1e08d96021dabae34f7270ded4509b22e13e27f72eecf6a1fcdb8fa9837b5f29fccad982e83dc54e148a7f8a0ba37095ae1ca7ca4e552d9121a87254e13982b2b6e6aafb6091e2140b0ac188bdc411784ee0b9cc785e79c57bcd37ebbf59f89d5424f3befa753ead6d7ca9602d2cd4fac142ec11ea35a59d9c120f7becc45f1f978a24f459e8881d2e13c10ad45845ee06bc4fe17d54e5bd3345bf3a33099f39f17ccafb72709fc2ef465e382a95e32a93d3f13b55e62a3cc6673ae35355ca8e4799232abfb5bf8837c6f19993904fc2c7003f5074c073613ca72c39375041adf0d1492adeff09be5721e9220cbe4a15befcba6febdf9828c4ece5ef957d75bfe2a516753bb4585e8bcaf31aac79d41cab60dd170a3674c6378ed6df2eb2661f98d7e945e981ccebf8eaa874115be328831c0f42bffd13df5fac2dfda62b90b9a5cf2bc8ff097c2ea3576aa9201f64a9c8d6fc6afa838027ab984e6f92dfa9849b15d3baff908517b76341f32ac87985f7665690cb7e1a0b3c2721fd58c57be2f688f19b6ed0cbb1d0b3f36bce07d47f15a09741e32c31bf2b672dba3eea814cfbec95641e48d56b0a363c06f87b5b440fd429c0e9d27510d2f3d9e3ed035aa7be2f44cbc5adbbff692711cc0629c59444698a3cc445e9bf3aed4de17169a04a40622118ea10c55d8e0e7544149389171bd3fb75ccdbed2d217ec95ef1d8c77708b1f6b39feefa0d1349dd3e42b45f95d1d5df96fad813fef2d66d2b84481bd36270d613069f3c64e02a3e3011c4421c6a5ad2218924d966b16c1285f345ed4148bb8d40b16e6c9a2de793f89aaa27e864a102b8f2ccb5a750046d499163cd0aca049f25782e137c2a9c87cc4a11220a2344c4425c9f5ff476b749d2535cf6c482c77ff841fd81b2af74e88a14c859c0b1cb320dc0c67f29a8f7f3952dd3ede6ec99edee12a2dd1e9d0ffdfbc922b8784bf254aadb75a6c91f5b5ccdb32edee6b1ef2f003e135f1906fda8bcc5a5eb2a7ab6e403c6afa45709dca4b7b1fc9201a443386c3cd8b3ee4cfa7cb19916edad212ed06f667b68c5c7435c443f9875d534bf791b1b924bc26f01e805e60393dfe58bbefdeadd638458f8f9171f5562a6ac4356282581105ebdb3820d6f01feee14485801ad402a002b01df11e2a7ef97edbde25669c1753ca824da22e7893fb5e9156d10377a139d3d3155ea784533338a2749b3b5d601500cba97eee07cd06972a24b7935e59bd62708b1fb7dfb5dd44f7a22dd9edaf74f6de590dd6bcca1693dae1562ffbfe4b62a9478cb35ad77df7fb89d4f6bb6190db05ca530e574908ff76781cf30be2f8bf19915dfda4eb06e057b046d629a2de773aa4e53dc0fef0fa37d2b4c3e2d69955ca1e604d2ad238ccf089ea3892d62f019cba251783e14e654f24415fdba236b7aac5e2dc40be7dc7be413d270f17ef56eaf437d07d5799002a9c1e697b5f38123cd9a62c58dbb8323173053fed6507fbb9f7db7dbf2ec97aff06dca2c35c429c9404a53259e214b14dfc9fa3fd34c7f4dbab657862c2ced295aeb5f14fd4a4bfbf2fa873cbd984efc6736c56f5c9658627e0ba0e86213a0a217933393be3d3d9ce8170057f4820650e6c6b4475c9618975b17ed53b091ed5100fe938d83e6f14b6bb781f9c0a4bfe0da99f3a65e2ec4d286f9e52b919e54cbb20cc910aa56db98c6d640909efefb5320d4642e704c797e3a6af51deb3ef7ffbdf7f8c3e775f33751bb2ab5dda17ec8270c4f424f046a00264bb30d4c287c51ac0013dd384cd08360b9694dce3a9ce7bf0f0c7dd5e238e991fcd0fe929e1749d8b7e3b707a609913a33756c863f84c9420f2cb6f1c2246dd917824fc2d57d194a6126b0f00a0cfae1c0c054f793a7528cb45b72bd791aa85600cc62aab428d46cb8de3375ef96e0b94cf05982f6cc447b96804e26f82c019f0a8f6db2478575ea3dda1223cb0b78d0b233f99c4aa13933bd7445d577f3df909ec55713df39f1f34e8a73aaf3a00156f30d202990f1c05127528f901729104ae3f525e4b76f574ff57baee74b474d1979bbfced5ab14bab9ed1f62835f82b259ccba9ceae528aa61272a0e5ded24f836893cfa63de88d586cfe7ff2be034e8a62f9bf672f9025a380ca9d020f0e13064cf86ecf848ae23360fee9617a2afa147366c02c6605b31ea2a21c2604c4802c0a2819942808778020395fbe9b7fcff6b76a776a76d8232afefb7d1e65efcdd4f4f47477e52a1c50011254d0beca49b2ae0a7d125404ef9918bfcf3ddc67ccce433f27117ebdfe0dbe60f765cf7c308325d7ad12125ff5e7230ffd0c8c9fc69bb1cdf908fa7eb94c5873c5f83de39ddef8bbc73e3d5433e6f3963fb601ebbcbc25a09044d888fe9681248110646f44d922f287dd4540d058f200e1905e596e29d8666d3267ad3b5c1fc80736f8e6aaabe2287016473e93ee3de18112a832c9433f870f428adc2537d448b41fa43291feef32e29d38f26c31cea481435244463f9775a36661e7f838521a678e679c7ed5066da47cf469fe32f17c332e252487208e890f408cb3bb6f434680c7f49373baa6df9539bb7e98a75c739f509df954040104354bc4a9b884798c52e3c6e7bffa8626186b162c7b6e3d050e529c07241092344a8fc7efa4d26a6d6005d2f53301810a8b332de8959655d079e3156e40696b6b73e326f1848e37fc5d98475a8761338fc954b13e158ce9e7132324f0258d9816eb404a904ca899e3eee1c15fe8c59f34e2bd95c9fa54797f45f196a3f461f65dc9bf574dd487d8f95b2f58a219c9ada91b9fff4d4b7c459b373dbd48cf6fe5191543369cabe77a6de58325aeae3ed77ac5fd8ea14ea189355c47e92a75a575b54a24a1da78cf1edb331f715e6211dc4784c9c67d3db6673ee2bcc4bcf882c69b13c0586648fcdb96287f9830e4990fd3f51a5e5834abe41ef3a07214ee6249041917988020d0b90281d0aca26d8591dacadb0a447fb711103c8854587c6481907060a1fefb9211b316afb959a97ffdfbb8369df546b7daa62c38f0611517482874c6d55599f007659b87b131c402d848975f88fb6cf4cd824966832095c900783f7487e4e0e71472cd7d01075f06a78e209b407fbc5f0fbc9f775c4c0004472a5571745005ab0a3230ce3ce0317dc93111a1ca86dbed14b8ddfa360c1f505675c669e5e33b74e5f9a571e68871e6c48f3390a092cd0c81849b4e5fb376c6e74a7d73ebbb978c4092ca72a8a658f280c44184830849590b4018d92b8719c804041b8cddd3dd00d91b4f7ca3db3efab7f7ac051919caaf82f1dbf4e43a357d3ee8f940c930d789ef84d43cac8ab5b62d41c7addf5c8cdaf6e0cb912a988088691530de1fd538373ea9f8aacda316ea03695561c1bd63aa94faeec2813d5e68a0d4cf277e3e65a8dec9bf2c1933e26b3dcfb33efbe1b988be73ce27e3d7fcfcb35273c74d786ea296e0667d3076dd58bd4266fefa7dff516eca99bc6f2bbf98a9ffde64c2eccf349e0697343b75c3adfae8da2f2d9a4d2aed98f470e30bf478d65b75a3d9af99a14c12416e13c1e1ef24f75726e623bc5df3919324c096e62ba39ab697dc6d4b50554d2aa7b881c8911b06bf936fdc8d54b949f41f5bc714208bf5cf2a2c100eb2853001a1144b11c00215d076b304e233a60f042c04a4941c9a13699ed2face559394aab5a25e2337ae411f58a43289e0eabce8bffe140fd17e9c686bfad238988f0dbc1a1bce463c08734e92334b628320954936ab76c039f838051a578e679c5244ee24527bf042dfee9c46e8b32aab07ee8be0fd7230ce88679cc93826da304d49e514a03a1be84b71910bfc369e67fae09c351e43c883547c52a511e49f4f8176530c219f78c0f0975ed51b65f9bb0b1f5b897a2de5a49a2255158ce52597a04fc64682cb0dac34456b5595e0ccb0ac5548efa3b6bd8ffb2c53cf586845ea9693ae8c9b570b57d33d03b76dd3ab6e04b95ecdb9d17e57c697eb998f64127450c47b8ed99d3e094a8cb7f2c18ac65bbed4f3fbc0c289c3ce576af49fefd57be90ea5a65c3bf28dafbf56eaf7b9d3facc9aa5e7f6e32d955b47623e4917ffade893c457e6edb30a66812bb994bee81e7c0b9f9cd677eeb14afdfa4ee4b9eff5f798bbfea7559fd557aade7e8d26ba755eeaae6aa85a3dec563c4c39a55e370fa396703ee2be5318f33316f313c6fc8cadce7cb06a96e7910995b99ff6af94fc839c5b32d8092113fd30eecbc4f8a3fd4d87aeebffeb16a5a6bdfccdd21f0e8acd57fc7c32240282f5ceaa2b8a6f5a64a08f8004b6dd4d40c20670c5bd5c401bbf9ba956217d1414fc3e73e4b2f17a237e78dcdc937bb81e5ba19f5bb81bbcbb9114f4673264278737a459e8037d3a63d3cf50b4114c9f921ddb6634fa5f8fb1d5e715954c65d21d2a890170336e2a24079fee5970224c007c1c79d8e0a9a6734090f712a5f6608e97cf3be01792838d71048d930209d724519d091b848fa0c624895cdc9738a9257362c992e211e137f3b765fefab4394d951afed880eb3ea9672e6095153616491cc489b10da4b981ecf688acca958d0de48d6546eeb1e91dd8aac3b7558b95aaf951edf2fffbbfb8f1865925553d9b1ecf2347b217e23ad3275b495756c59a7e500eae205d7b4040a9ee1798be175fd5db15076d3e52a965dffc36fcf3e95ab298f0ee9103b464372ffcd393335fd273397eeb7745501e9623a92879b9b16a909c1630dfecac405e6f046581af050212613951ff7f4ee9545772fc7dfcf4450b75ffd737c6fedfb097b5a4f2bf669b975fa7094a9786d35bb9b9f73e4e5d52bfbef2d93294cce955fd9c6489e7374718dd837270f99d26bcf8fd4e0863813f1c8fef8fe7e7bffdad5edff3664fec3717de55c40095d27c8371622fc3d70cac80a4c25e58309ec7e77adb76dbdd040403600984fa03012959e05840dd6f7c7dcbf4dff402a91b6a78d6655f4739ca4894d0c4447d7377a1d8a031ddfe403ccbf4c998c939b070e0efacca6424249a6c1cd06b701006700a499304766523a699a5ea1bed22629ca6df1d0b6f249c0562a2b10dfcb9789e8d71e6e279369e978b7152dfa8009bb2e440787a88fb7a609c36c69998a0f68117117b272551f1c5c69981e7e5457fa7fe0fce6dce051ad4f938eb39bdae572d5ff2d15a24916495155454c481913b23111096401099ce223e558a8c0016284f7373926de8f867c51a3dd3ad061dbef4262df158f7584535baa81867db9d9d43e83d0d21118c449c243910d7997e80adc46f746709c4cc73908a33c89d54d8b4365eb9a6f5142d6b7ffdef37cf78aa963ea88ef8e98e5ff4015d3ebae4fb121006962828abb17087269d3b3b2790ca10991b28f29fbde128a383cc5146df074e106404a6cc10e557e843f0d9cacfdcbfffbe7cfa9085bf2b353bedc71786eb757140a3f6dfb939e46a3fbf4fd6a13747e73dc3cd6abdd339c9644609697497e78cdcbf7e9ba1c147b69798d13dc3831fe39df4c257a3df5fa6d7fbe38591b553314ff41d48454b8419fba0e45ecc1b083d491eaca2a53437052a49db5391e814d90b33334572bb91db6ea3486e37abed84a3f2374efd4abfec1d251d877ee389e49491ad3272d61b994cf5422872f61a53f17b97d5e26e6922da93d6e2ae66c4bb1e574bdcd7d433ee6435918322f37b7104bae127fa8b08f7ea47bc9b3e229fe3e6b7bb1867f7f871aa21de1af71401cfe3c4fb6aac8923e91d8e78cff6cc4b40c4fbaa37969e30e609a5664d19f79f455035957d602067d9ad0f78adb75f3ec30b2b071b58b5c140e74640c70bb9145013a5d63db77c909bf2a4626ee9800fdac67f7facd3e7f07ddbfb22c8134720d33cdee4c8086c83ef1ae0eb9db8c6bf9eff1d8a202ffa6063c96f9a00cf787ff4214f6b82f1c569cf5ffcbc9ebf4d5dd634580f89acf41c038bc108163d6de0d62d066e419afccd389036773170d326c01a8020001b7f42ff0b40d89c36e2ef9b7ef2fece90aeef25f00f8b3da7ecf39233dd710f1df674c4adc13eb1df975bafd4e3da6cafff6c74e7f875b5ed08722728a25e6694101910f4f9b0ed08f2dee25c9119001c276cfadecc0f5b8fddf4e4efe97abd6ff8717421050652660c043af3b94a9932a89c04dc7cb9d436f5b30021693bb35592b6bb25106a1103b8e21ec111806b705d1ff46f763db4d2de99fd88524dd20e987e855e20d62bd6e7e97ac21445a6f60307c691c9e0f038b2d54402732dee4b0d3dd57caf4985c8b5b8d99bc58c8a543e14f1ae0222de6f374911d56aae5b427efe05e89be7cb08e230c63150f4fb21f2be3bc67517f07642c46a2c92dc533b9e8de532e2fd24d4148f457a2bdc9781fba865e03a85eb32709dc275a68f4340cf5f187f3792c85ddedacd7191be729c32e2dd685e11772b23e9154792f3381346bc571554dce3aa4e46f47975f9b3fa08dce26c98b7f94b7349e9c10612a75c02955631245fca75553addc032a46dafc0015709c9a48a529d08f746ae24b9af81218ddfa9e5349df6ac7ecda733deb866a9fe5baef559541239dc7c5f3dfed518ffb62390791e5912c13ca27f9cf922d65052a18a752a3309248920affcb9fcd24d1d95ca5ff7c45df7e87db7326ff147cb911eb21c84b80c11fba5eb309f3f623e3f0144a1ae22d4d62f869341515df451e7a6e439c06b808ff09224422a97530141c859a5456ed894fd9a545a22f2ba02b6abf217d03f52a93f272cfa6ecd214afdf2cc98c563c24a1df65cce92933421497d38edd7a6ae8c4d11e4f062d4fb8d723b542f829cfb5c86629b11e4b1887781bf9023f60b300e05fcd1fb7f9ef5c5d32f6a867b79b7853dff840a8a5557349fa980ef63beb09e4bb02f2a487545297b28b50fad7322201115d0f61401a166036618e035d3aa98bbafde226b1e5df244f1c94ab5a8dfa6cb2afd42358beb6e3ac3a5a40538901947a0ad804450eae746fb1d38421b8184425530b67aaa03b6a1d838f0abeb66eb4fff6cfa490309ab19a0276c05d5284813c17d34ce8818a71dedb2ea05de66dbeb662b03be726143228297345ec1a72a88bae9fe725ce4ce0177ebb53e6edcb5f321519412a40d035515a952d86d17aa167673a4c2515718489c1a07564500330ca037a3025fae2d6fedd43f46bb3680d6a5471fdff876bdc51aa71edfe91e97699205a5aa1d319d2be623037d8fd7996f9d4a95a9df6d3b8aaff2818ad3dd0aa1933e1ef6f9139a43dfb06ee5cfeb9ef3ce07ab0071c03341862e9de695e13c5c0f5514ab08bff1e223a706b66d60de59374f91d29502e23a4ec541bfcb026eef88df2960ae0a5073e0ab9e5e72f6587dce64b63eec8113f57852de4ec9744b39fbe2a1aa1b419ed49b935494c96c7dc027ca4e14e56fdce4ba3d7ff9d280538676f0ce1fbba5932a906c7bc2bb909c4868fe4875c581b211c002017d6d4f131034e62a3d5ac138481b72ad528ba7cdf86ac179fa034fedf8c57e7a81a67e9a3ee1d07a71c8329863b6a3f792d191fa647ccf85ce9ddc6e27c37ba5ba6eb6d256605bd124e09a90dc84fbbc8184c974d0d2a84d6ebc4d038c77d50cd08b2bd87416f0d4c5b8c3b8cfc2f3c2783f2bc938cdc2ce12de662ad0389e23c69923c64904561ca8c9e215bc04f5cf768b078ed207d8c8b75eb787233715a9a44a5090ab14075909d93ea84f5e57d00d13c74a070f7ba5089515415ebfe00a99f18164e3164eab5559afc782854a357cbbc5e357bb6f3c5ddd977a9d8a8f7bc930ef19e81c61e6d5efc51789f6b3b9a0543fcc8fe907474c7bf03ba32b2f2f1ea9d4d482afee7c7a88528b7e9cfefd6252fd1161a5c0331c3825703228c6fcf27c1e97b8cf368fb82cd56eab808e9e22a12bc88d14849a0fb6ef13c34a4a6a2a74f7fcdda0aa61f75452ed900ae7cad87d9bfbad9ded8e6fd3b2353d22faa438b0ef2103c28bf5d9d3227471832312326a76b4e78f5bcac055f84e89d76db5c30e0ad9abcbac2e10aa5f668f7de31dfdde4b96ce99bf6c901918db3cc82961be8022c302650daf10f3cc95362380052a49db4336106e1103c8482337267106b4107881698ee4fb4ff3163fac5fb47c76e9b3df8f4e88db8ee28ad58e367daac59d0fdd6577aa89ee84a370476b71dbb095f86a713b36f043b76cde3ab0283e6645e3e91d3f2efdef1831ce31629c63e2c7453597b9c67b6feffbc7d510878d2171edf8b871f6f68c13f3c778148fb3b71867e2f98c8dd3f4b3a846b8a8711f3ccee82a595f77e59d939e52ea93ab9ef962d0523312aa0059d6c640f23e2925ce998cb5a4022115078c88cce9d201436f28bd5108a2b1ae98d631d6b5bb8e674efdeea11583f5613b65d3f98f1a55c21c310f63f09e61e0f27c6f7d1d7d8f30aef3ce2b7f0fc627d7a917bfe3c5fffb05d3bb0ed4046f61fe9435bf8333a7fd26032c892014df23fac580d0c1930a8bbddc4679f1b1e441aaa607bdcf6548bf7716bf770ef8fb775e4878cbc5f727899309dea8d8f87f9f30fdb83ff4fa99f5d4d883ee18aee7ab8b33cd4d79c335c855e275ecfb7ec135f9e97b1a7c1151e33ce0fbd1be58f79f95ff9a3449a91f27e40f9b0a1521a9a0f8bd1ff0ce17f7854447e72c9fc3b4deb3bdbf276f7f9104c2818644db491229f0f64303f07b5f3d099f96bde94ef5aa39051b22b65207fc9255e738bd10429b5216366feec14d58c2d17b93051206b903077ac770df70e403c876b29d6eb632e27d2cdc6e3b89d41e390192830a901c689c9475b79ade66dbe0784d9f395eaadc4ef32b6b65cb88f7c40159d50e248437cc96633714cdd1339d5ff8d4f8e76fd59be3c9d247493545eea27c206084acb2a2fa1e929040f4272f1e4ee5f02ee0558074841400da06703cd340efef21f42dcda02dde7fc6cc5f6729d576ff63d79f3d59ffb63af46713f70b0749ce314ed46009f236cc467f8a74271539b8622a98e8fad87cf9bafda7efa3cfafbeefe70c5985f7874a880ef6629224b0af48a2639515b93fd3bc929b2e54246493a8b8dc8b9f5548240148ef1f48404c90a18262828eefc18ca8b85e465257d1f70367cde518c85d15df9957aaadd4b225f3bf5f7ba852ad738eeceb9e4fb546d57df75823b1627e93781f2697282378a657a2cc10f811f15ef95179cb8d1b95fae2df2f76795a334e4543370dde0aab0c49d0d20d9dbf8f9024997063fdb32a8f54b479cadb222a49fb8b09888fb3cb330089b0a31b300aa1ec71376cc9335b9ea85ca839d10bffbcf05b4d699b9fd4a676c719fa5566a5aed9bf7382a7d0464520a13eb648076d12a7076dd06411ef64cccca2003645c74904ffd2016dde2e990d82fcbdf3456a8fed0dd02b64ddb9b131b0d15d2c7419a0e7cb6924547163b9846a4f8cdbaed638830a4b753504936d510139b836ffb06ec22fe729f5e9c2e7c63eab0fbea29f374ddfbad50c8ce2059853ee6ba02420acb222b7533ae0c84d57a83ef860a2b4ed71e9dbe31b138e5cf433bdbf87f48a707eae7ac435801e909675836bb4af51b3f6a2330f8c435280d51fb3b999752675e103799ddae89be4a04d45812abf4d2f7a7fe53b9553b76ace7a5c8d8f073e3345cfd19b9b8ab7bc82f90848f7cd9cfa5cfc0e022d397a72df65151508728548d247f556e4c12f09b3efe0a27e9ee8033a825030be3ceff3e877ba8e739ae1b9cc796bbc8bbf9ef9ed2f33f5f63ee9c4abc2ba9f529cd2b9996bde962aa96405a5628c9a8d7734fb69602023e8c137e3f8efef76eb0acdbbeae73e0bc1e0708439158822b774b23d918d4fe476e3004d4a5db2c8ffde1e98b4fd5504845a9e01c4c971a0a1e8d3c68c37be6ffd76c3603797cbf2b1f3cffc5a4fd4fe9ddb4f6b7d8d52a91bd31a1e7c6d8267e52bb8e5527a73dab88263080a20923688eeb0310c807f44925adc496d1063d9ebca2cb01d0dd00b33a112a933b633402f281dfe94ed0c240c26a8b9e63e11a782036fdd0b2bce1f3f5e7fb6664f757da991de1c2f6fb9bd085e7b4c38289e000759710f4088f864ece500411190c61c31447be67ce9c001a1f26da802bc19181b3a0a9880647aff1e5aa2d48a090b3bfeae39bd8c9cc31f3a42738c29dfa674ce3cc883d360cdc0bdc99c43b24158d690d34560c474ae0b96a6ce993ef871a516749a346d16fc838880b29b33248a22230bc76c1d225e866d1aa492a29c4a24c9615e1d92348860900461a3df9bdfdddb643fa8d9de2e7b2a45c4f3d058699c873e7de730eecfc5effaefe545a5eb5c09a6ded0c68fcf3956a926630e1873c9ab985ff70bf873c7d9e8e79a3ef63d4b94017161858919d6b2fb4ad7ace9a0d46739cfddf736dc99652a1e628828ae83bf13314ce4cd86efcbaa404884acc222d5556feffc246f7bda0612d078e061f4a54d041b9c757b7480e88363cbaaf5376cb953a9af7f7b7d7aafdb35c77aceda7b5e772732a22274bfa7d9b00df44ea6834e6283c857d103dab910bafc885797bf1dbafd6ce0e92eee0b639c5e5dabe3b395085d39fa725cd9c2b621c6a96cdf389d78fc2adfeb971ed3edd2fc117ed18fe9f4b33de3b439aec43ce714e747f7205fd2744eedfc2ca586bcf5e4b12ee7557e4969334a0ee79338b07198632689438aee14e8465e56a40b26880d54253931aaa419d078dde27ab68190aa04ebcf3da88b9b6fea553a48a91f6f1fdcf08695fab719654dc68fdb06eed8f717b60c87be07e28fbc362227ecb541551e51b160cb1d4a4ddffccdb01fe0564b121707ea617ed87b4710661949ce8443d828a48ebd4ada88b2bd9079701b3022672149b3bd909f13a0d377e8bbd0381ff28e9fe6a13c2ed9e60ffb7e74d84c2d01977f5cf2c44f676cd39611463f823eed2fd3e7f5bf6d1b5fd9d8b2e3dca49f5faf7e7bc163e4464dde700fc4c6e5b6d280b204acaa123611b2f1c9f991f358fdf6574b20d4228921ab08f2d00787c91c838dbe9efaaa0595ebdcfb167d31eda9a9f594aafb75a3bb7f395f73108d1b3f78821bd1bec0ea5c3bcbf3cc0ce08a624bc0317824099fe49005afaba190689a52ea942491a8413608728bed847a1bac3a4b5a235a7036901c46727c0aa9a0308b4272c809901ca4089e2bb2c006e5e00af62e19eb1927249e67033dd20000800049444154caa3ca87ba1b66f26923af7976ad3e60af1c72f658f7ca91ce264ebb4e1b8674bc50a530c188338646fb58d7e44dc48483bc73c8ff9d4478e2446df4893050cc49508b18c01274d8db9792734813bc92f95b4a5cafa0351f2cbbed3bcdb1ef5fdaaef258cdf18756a76c6af140c267640077d8e0c6aea0dc5f6bc87622243de4e05af3e2d2b1a3f4fcfcfef2d46f669c6750920a8f732441a2209bc756a8b64a496585dfd96b8d5454940e9ceaa5d07c1600d2c12de6b7da12c68eb608609e80384f1cf1770e27a0f3260c988bbfebdf0fb832eb3e37f757bd48c3b6dddcacce4111e46cd3622fce0cf38c00491dfd8aec8affb9b68ed175deebf2689a3ec78e99f1d41f88df609514f601bba5cff3f6e93b9542526155ad34a2c3fbca2779d86a3bdbdf4402e11636806a4f578d07840e95bd2f28bf3d71a4ad0d242f91a20c7d20fdfbcb5bc7eeab0fa403078f3e671f2d994c58bbe01d3d7155232b07accc8c7b26710c4111ef170644bcdba8617ebada662deeea46bc3b594e17f42982381bf76db366368f5346bcb7445c697f6f847a825af10923de7db5e8af412df9b037925e2f3a1a97e3196740647ee59d95735c4e7c79f8b7b69f6a517b48a727b27a757175bddf1d3313077cf1b3800840db8a0379abd1faaba263007301efc6f51420380d1001826ee548b75520c2bc92ea7b50e01445e2eee046a29aea24b1502df5aa8f00c1f9961f65a04b10d79eb5aceb86054a7df7e2db9b2fefa5d4fa352b8e7a70a6be765ce5a7cbae49f010b94e6d451910bceb08dfabe2f48a6c37427bdac0af5f183e09cf072165c9830e28cc13a9a64ae877ec2bf26ea3e492151f1a58f92f406494a00c13d2bb67bb258b5dddc20670a09c5166b3719e22b8697dd0f94292ab1b883772c1ab678eeaa67f3bbaacdfa433a3fb26610479dc3e8d3e554690d33950d9a5a2b4d82d0075f382673fff4ca9a1673f7ddb9d13955a78c2d4cf0bb19e4b4cc873ccdb4d7abd615f9420854929e277caaec3f8b1ee99612209846c4f36607fff9455affd5d2410d9e88550471ad60ba584570ccd83036f12f2f776b061aa36eb491eb4e93d97822fda326dee143df16b2e583a6aa4a6f08df25a6eae5d5ba9f409355f3bf860cd096cb55a44d34147d8a869227fef0a8878efa9aec1184d2470402dee6dd43236c917a9667896157d5b2dd1a076322250f31149df097c5b4fd4aceec311efa62f22deadb7e9efe0847aa296791f964c2ec2fb7922dee3bca32ec2fdc668fe86ba0ff72170922d5634ce0ce051b82eda776654f67625855537169eeda6f11e7dfec0d00b6f6882317bf449938bdce8d8e2a94593cd2da5f06ba70d41b078898145308e93bb28110cf63a815b6f296c60954702526a121ce894a2c141ca0d07a938f88db6b751ce029258f03e9cc0330c084e922bc7e8755a5e5a3ada4de9535038337f9e269c4bface6efa8996c49aefdbfa81ba75f4fa1c5cf3b5435c770fcdc9227bf56a3c0b91ca58477db8f67cf47b6dbc66f5e73ff4556a5eebf133c693919b2295895060be8a6f01a448f25c5cf7878144402ae840fad9c02a404a5144df5eda1afe360de9cef97cb1013300c1a038b6ffbeaa82aa37dcefdca6d9d1fb86f4795173459dae5d5c964f4690d3faef09c983ec323817b6feb461c9af8d94faeaeb37521ed18469ca355f7d39493fb7b8ffe69fb69888320e842d39d4c0adc420cdf542fa7e25fbe0bec30d2c0781af4837d0976d370c4836a2016a079bb5a337eea1661b40eebe246a5af0b60941824a79c4c0d454c0470d4c433d87f4d30dac09d1ad065255d4d222e9be3533af6dd64ca943ea865b5ea245c17aa58d979fad3772e8b494468d1ac586e24b72689b842c7a81a060933517630dc78f3ace3bc6abf2e923543e03d0ef095584ed353afb8cd0d20d508948f21ccad66ac6b51d11ca89555159f0fe998bf0b970e271563c593e73fd7abde7862ca9fc5e733c13bffde2beafee556add172b6edd0486a092b2b5922449ba5be2f8c8dd561c783e9dbc4c578d03af02aa1ae6bc84ad43eacaf980dfd9063cec9e1e31209403089543da1106a6c206920e5d37adcb1ac8fd54e309a5da1d7542d7767f2a95f951c70e376a0258ebd8ba634f7d34faac309543c0b3c3e6d9e6e985f7fc7ac7f35ab298d26944d308c6c1b643d88e8a88a3c5a147d97437dd81eb288219f3cbba7472772677580ca1fa69c0ff5e8dbd3ce93be1fba588f3c44da514ae77e9afffd292579b4b8e29ffa98bf265809049294b4ed9faeb6fcd959a3f67e2ad6e4dfe9fed2ffe37f37c838f032729ee4dda38608ba11c63ec05777c62c8650828be895457e40587f54e8cf6ceaffbbfab04422d02980748bae602c00cc031dedb7c015e8bbdd7b9c9efa2504b365b2b364c2bba58a9c54533c64ed3a2e4c24953d33fd194bfc63575be993f5f2f9aaf6b2d4e75bdbbaad2fa367373f9740bbdef12262b56f02a7aa0ca5adc49dd6c65c47bb6a8a827d377e724cbbaeaf54f8fab999d386d7d6c9c1918675e140645bc537a78789b390f54ce710f9c4d9bd67ce88af4f39f9db4e103cd517ddbeeed7fbf5da5d46f23274d706d50c5f3b78c22b75b3606524a05e45422d19b75b9e455026f124ea141de2564cc953a7910204a26c77106bb9b70502bf0e225ee9374ee1671a739e2f964d4cc0324ce30434bcc2b962e700b282d7c79f2f831eef8dba84b7fd0eb719f679a5c72e0937a5dfe9036bba5cb2815eaa767c6b0cea933aeebeb5a32db327cdda68d4836c8f34e11cba433271d3ba57ea182437410891421aca2c230399ec29613b297b488b7cb2c19be1f7d4797d014b69f7dc9a61795ea58e7f4f3720bf48fedd40375bac6f65fc9595bef9bac25d0df474c1bdc5f9f2f5ffcf6e2b9eef42c1b38ffee15a4faa3c03fcae54569efc93984e26bc0301161a78c00e49e5b2ee23b2a64ca161161ee0b8c2d48381bdbd1feee12886c1103e23f6814e2779248429048524e319038bd347cb0741c3c35e07e980e512f1d1c60da63dedfd3c66b1cb7a53f525373846daee8d4b1dd4aa59a6f6d5d7292e66c6bf5ae5bd1467368e967d6ce3d584b2e2993537aed333d36aa6a4b0e739062b22724073b201ea08f90246cafe42025891d4d0f5f59a762999b5caf7c63c9d9cbaf576a73cd75bfcc7b4d6fa06eb38e9a3849138c777e3e72d122b75a5fc585c499929fbf2f771179d151d237923c90f48db2e6b22421385ff23e61ef128a3778d00b2b4d3a4acef2bcc70847508b18c0ebf566035390543024d667eaa906b2e44ceb1212740d482ae990506a6e56aad5c8c31ecc385ac38687f4f9b726dcb5ebd5df98b55aa95187bcdae83170d0243190ff3f49763eef35106e8eb301072c250ff66e0c1b1058437b2f6b7c9ea0cf1a0e30daa9a719983e41a92b3eed3bb34f58cfc5a4cacb5c82baa4e79cab7fd0d78f3b20ff8e25b061d1f723092605f888a160db2e24058ec711927711050eca887eec2319cfe4abef21bc0b77ddf7dadb0808b5880124724a5581057745df02000746aaaef4cf0de40dfb98b7cff0746f5f6ef45470c6295a826970e2bee3ea7753aad1c21637367e45e33ca3d6e3759ed6b071cdc1aecd25f5fbf4776b3ea52f1e6ff572c76b7550b746399d4354dba859f432abab7551ec552963b16e207fea32ef64982bace1dc37ff759f32cba8b3155d8ed665e63e67ae7393bb80ca37960e71dd5dcb528abbbbbaefd2014583dc0364cdf5cb2e5ff789521b5baecad82a74da94fe9923834564af8f7090682e52d33001211d3b1112e2a888609ce8859cb2a2b3173fe73a42dd0e075e447f19e1902d6200a9b6422028ccf08090f03ac5fa4c23c687080741acbb1ab0f1a4c3af3f158c133150d4e8fbc814179cda0384830f2c541094f3cd1c2d4920d20d746f6fb601fc9d08d2f7014c032171558c513801f04903ebd4c175743ee07b90ea9d244e522d717c0649e8c438a14fce419260f07d54d783548b58f755c22964d713fabd9580508b182009090770914e9308c9615e980aa3136f5810102610c419c21b2c6dbcb89e16c8a780500d50adec9493bdcf67db4d8e183771a8648cede07bd33ddb8840d8807410531d1778b3c46735755ba5486227e377e401560e6f114ea34e816de5debe8c33e09c5522c29973fc8401ff6ac2211b9531803157ae4f863f1ac89209ad37b10e99a010a7fb88170fad2b960c313fe542d7cec91331efacc292849a525e8481f71f2279700b1bc03657fcecfb2ec4809e2e20be43ad5ab88e248f142f5e22bc559280906a8b54b4987fb271c81c60fc5dc8c64784ddf1becfeeb34da5ee6a847bb8850d70002deadb06b20a031bd5c142a882c4e0c0cba10a1fb8121f9c3e7c05e627053ac854b88fb24a8c080844fe14480129901a52f03b4b4404a9c200f02ae0b5268b7e8edaa38d0f5c8ccbc1387cb98928fd33057ade893ede9b0f7ae26045c05605d5c87e0f7d72b3edec85952778f155e17747a8529c30a074c70d277ccdbfaed1b84c121d5515419fd627cd33b95b82e1a0f5c9f34db5ac6104a7832705de3accb0a02f8da7155059955344f9d180142f83038c395a1c74be38193bc13beecd2d6200c789d0814f8498246e3a1fb01e2d48060ae7818244920a15217f0fc22308884c1e4b92067de732b87f57e2fb5491c41110b0b9fb0907b5bd5d02912d6c803701b38a25b9830eda221db4e0fc885320af2e3af049224911a26c2a9449a4db4cbd15fd1f12e36742421208cdff58316e15f01ebbba450ce085269a2f8218aa21592783d36dcbfa0d32bbb2c87e5b3113f0bfdeeb181f491a528516c469ed2d075bd800e9ad25555c969464c9b607c2429c700a189a1470c8b46e99e31591d8940edd2721922e9e0e2a996c0fe3fec7491eb2850d604984f62bbe0b7d8f14712e30630915177d0fb68111a3400484f60b7d0f620cc43e621522ed071167238de37bce1b6e6f9740648b18c0eb1b134c924915fcf45955441f000739492895d8a02910f52b2142a6c08d2e04513f85206d6c10a0907033e603812412aac468893ec511900d049ca1daa2764f23fc22e7933c881d3c9fbc6d48b75a0509c58db78942704a7cf0904a8b36c828f13b119883c47d64fcc30672285755588c8fc6bbb7e9e2230638610359720624826991bb2511568af8a66478a8049882f52955a5167e575049b16e1c2a2b2e814a121d491cf83bcfab7003dd6be679475bc4009644b07fc98b939d08305f0adfc3c139e040b2e3ef019b8682ad89093a9c45f87b200ea70ae70a13187c47a74a3c5fdaf8a497d56e6fff3402225bd800aaf5ab1090a668e32020870eee2a3ad049e70ee36e08128b850867f2e70f81530b216297bc6bacb3c47d504d8540182c04c4b1044204060190aa55d237db3ded2a2f245520135ad88eaa28e00a91d75517a08f886cb6912010902280abe0865d05c25c85646f74305204b783bfb304d45d8c8772544112dadbe20eb8450ce0f5490736a93a6c40bca745019158375520ec15f062e3f586804cb6a521a2994a94b21304d9b41aa28fefc811fa34aede025fbeb76fd1efddd5ded9f03e5c039c20924a2a042ad33aacc2fb32e389b80e0bb63c5215f2bc50013cda0fcf7a9f47dfc181130947f45366030a80a5d2ca14584deb251cfc6abbb7fdd3090835923810c8c6120a1d40c268cc111644f1b1404254a43e823eb295b24a0cbae310227759f4c586b6f6f1f65975015b8005dd342db4bfac8150d2c1c32a2c44ca3acb00893382379583dad3cc61e1c0639d3e7170c4e92215066f20da50b6f7b9ccf1ae12e39c539d97d90b1abd876d00af4ffa0f312f746054e180b3d60082f072f4f379e2394845e280602892ec40c09930930414c1dfc1f8d07ae7030b0c183340bb5be5ba9b9a430cdd50f13b1110aa4bd453dc88f7ad0aa3ff27fab061f077682beea3752f55502471df0848eb9fbe3fe2d75456c2d7f80bda3fcd06b2b32d62007f781b7dd2855adebf87a81f4a7c1dd93aa48d435ec73a57e2ec68c1ee6123ba6cbe5c4680b2029f34daf1df49f5618bdf855717a5a2f1d95c8274bb76c038edc057f967b48801bc2e88e3c7c1266d68bcaee43a0a27c61bf8f7b0c06f0bbcd4efa312b748c038f65093ebd4f777a9b2a5835dda12e8ba1cef7581f31b09788e7cbe7c0e8d23c9b8fffaf6ff8b0492acd906c885604963b72d206d1821babb3aed86afeeb74fe854a58e79ec8cad75ce56aac9432d3bee73ae52b50bebdd55e75a4d5c5aa62c8e1ad95e77d2d4f59a6b79d3f9dc72259d03f4fd86e3eb15e55c56eb63d88ec30d4700759b35573c759ea77bba7a31faeb8b94e1c7fcdd5ac8d79bfbc9b1e0e618e668ffead0b7ee73ad5be80a15e59cac2f4365d1837d95bacf95204a5a16854ade556a43fecabe9bef506af2daaf9f7253962cf978eebc0a18731dd8867c2534c92b8e6c1e82c028499068e30a6f1696182defef7bad6a2ba8850d600905ebce92bf538b00ca830bd7cb1441ded05215637c88513a3576dff1cf743ba2865e59077538eccb7afb2a556765fdd13517b96aafaab91e4276b1732dd5d97055b34e4b6768743ddfa6c0675bd138796b8142bcbc65e4dc5e588737a1aff8efbfc5bf8a55687e2fdfafec4cd7bd7bc584df5fdbfca552e353beb8329a2961e1daf57c109fe69d176654e81c0474e065c5eb16467207c673ae8d4ff3d4c7fb3bafdf20afa8b04ad898c0fce5aaa9eab6ff5f2510da7824b286016dfc2e378e15fbfd3ceb9661753541c8fad709bf759dacd75c4afab747eb051bea9ff2d8e1b7ea6bda85de6ef387eebf199ad8c20d5cb454dfa85153e696c253e372e750295b332a99bb4a449cc7e1c3a8ab9d0bcb06be1ce08b005f0ef045043e1bbd20fed2db7e503fb85e3d55af55951716ba2e8f95df2db84ca9d29e45ddbed71bf9f73b674e1b79b75279231ece5f4a2a32d2bd1361116ea7acfaa2be9080b84fa27d77efdffffe1b71275b18d03680d76f90244d90eed7fd6b073e795c132d11b6fcad4df7cbf4ba0df54abdaffd0d1a8e0f75683b58c39b42b96d96b96a1c6b79e368a4bf35c60d70d4abc53c2556d1b20f9e6146c5b9d7c4bab2d1ef233224d8de0a7efa5f83bf8fafefc527332e387a5968c6c4395b9db3e5680d5fad4a29cc74d54b1583172c50aae2ea8aeb16bca9d4cae282db3fdfa8d41ba3ee9ee7964c2e1eb7e54d760f172a26b91e7deb8f246e257ecff6e2f349d461b597b6ffdf0808057291712b82be543de925fadf55cfddbaef6b4a35bd63ff79975ca209c592d48fcf9be94a25a1f1c70c77f977ab221a21dc412e6c2f7f973449219a950fdfb08b387715369e0f9f02be08f07937640ef7e7603c1d802f022c1e3e3330d58a4c918292b51a5ff5084950d31bdbe5b02a4696771fa30ffa0d9fad9efdde337a037f78d7a4e123945a73c31fe754483752f2d6a20d4c8183bd459f8cbfa4331692c83f4e32b10d88cbf86afac4f044445fc3bbde7cf78dc30ed392f0c6fa4f5caa097b4af394a74fd39cb9f57ba8c6a1435d75acd5075e5c8610f8bf7bd8e016a97682d6ab95842149ca580510a25dc5f0a039eb9c27d7eaf7aff8b1ecc2715a02d9dc6ebdfd4547a53ebff895ab467dadd4ac93c73d568cf828197f210b8871802b412240d2fddc06c41bec7debf39f4e40c206f0d224c98308c9c54ad56dd3e04bd76ffee606afdc75c64f4aa57d5ef38a1b87e88d7549e8a6d3ddc8f453acb1513f7b5ae8b69018628423d9c11fc67d3646b3472486c05c5882d3f3718e010470473768b2567955e569f335c15e75d992268fe979eff7758f15a3e00ee9cbf143fef244382820eb65031d383b54495d7618fdbd5d32891840465d5ecf7184e2922beefdb46e5da55abf78e491572f8d265d2cca6da599a3f3436f1cea26b16482c0c93e693d58e887d10f627c4cdf7fd01b7cb1c264169ee2c1c77d99955ae480f311b01dcd26bd83cdc972c66efa424bd02d8b370fbb5da9826b66a5bf71b9667826ddfdf81ca485e7754801b314f84a714b24d190242d55b6c2b6e7b3e94576e60d7667fba712908801be1427cd946a92d3b224454b14d77ef2d4c8f3ffa509c62b356add73affe5be75051c78edba12aa2e4871d5073dcc6c1df67070ffe7c98d02fe23a1c11735da0c460035fe2833f1f7fbf88379e8dbf6e2f2769eecb0781bc08efb98b3668502bbfacece1896728b5f8fa5f8f7f3455a9d786ddf1d464533d3d963c6eb4e8534022a9c468a312874884c3c6efb451c3bb7efcbbb4850d905e4e1679611da2d4559ff57dbc4103a50e98d86ed04d599a607c98fae9ad6ee5bcabad798d676d839190ebcbf2fa545583f1d9397cbc7eab8dbfba8484f027dc6f3bdc5cd5983ef8cb524be67eadcf8d82b1b39bbd709e5e9f9fde71e1346495e688fe208687080af5a5ad4f12149f71ebefd252feea01eca21636804b8912cc34d05549ddf29ffedf645eadd48925e71dffec417a832d4febf7886b2cfbb7b5a079f3b8859821544516a735370b310f7fa1c24d362c297d50f64a9686f5951a1584240fcfedaaea98ebf0774b6c1c2a8599419c19927767066ca0ae286d4b7d4b96c6c5719421383fcc597464f1e3eecaf8bbe33d88c02acfbc64c630ec4c4bf9352567ff2b946a5cd062f9a5f3943a36e5ac4eee86fab1eba7fb4cd31cb433c35948df990237991050c1201a4944f40bc4ef79e2f7825df106bba0d906706967eaebf768f8e4bea342b728d5ebcbb786e4dea954a3b1cd6b7d76ae9e8bd2948e679fad5c9373ddda37c57d97d8411cc5a2bf5e0f6033fd08fa19fcdd33cc7d62fd5329d70c71d05b027f21f0c54a387bf031639519b0bf72846a3693f1e761fc1918ffb6c71b542f6747d7a9e56ae5f4fa74529bb63e4dafcf035ad4bee24da5b29b77ef79f0294a8d9ef9e19bdf2070308400d910dcf42939236708a09185f1bb0d18f1fe9dbf3faefbdbaccfbd9e80840d084c09a1e11d33dfbdafb3e654eb5cdfe0eee1ada21b605ce793a20bc9f0b3969018620b3d8267781762064b20c6d9f622e6e423c0e73df8f37c12430f8cd13c9708d61cfcbd13fe4ea27b266d742131f410124321e333ef910fefabaee63d59b2caf4a9206ce0cbf08cbb5010c07cd411e96af5c3dd1909e7656737a86c6e253e8db9e69175da9cd852a9cef75e30a8ed754a2dfa78e6033f0c526ac386d55f539d0acae1c592751e600ee3327fcef3f6a5fbe45f5e492f62001f1c790684f44a68f7c1b193dc142657edd337edf5e7dc3203a9a7f72ed07f6c667d56c7b576c56ae0dbd19b32a85e4c1023216aec5b98bd0ca1eacc14eb97189f1c5ccf12297f77c2efc5470c490fb91f02c6dbc3871ffd80751a63d4c47859f58afd45e3e78af63bd6ac284e95ba5f7a797b2df9e5fcef92ff1e778f52f54e6e3479da614acd1b3671e566646ab010c82cbd3bb9767e2efa79e8033221e983df6dc0c84e8d7c17b4d05f3d801d6c949204594de9bc706d19b73df2c6191d224add97f9e1d0f73fd007cf05b53ff9de55750c745e77bda29c5ecad41e478deeb85ae261f33b6a18a3c6b4fe48a6e6346a8aab21a8817c3a6aa2f752de5ae8ed4d9f6b8ca346b5ea8d38d608d730bf49e0cbc275a8796daee71ae543ccf50ed76a1735d01df47be33dbaa3e42ee313b5cb8770adf230f0f5f68cdbc17b50adedee2a2b1ebf9e97dede7911f340b5d667735cef2e69b5dfadfbfad95395ea79cc8ba3bfd51cf74dfd5f38edac2bf137e41eaa81ca93e95f1898b6dec054144c0a217b72086e99e4c0cca49502fbf6df9523df46cbf23e979d3a9a29d5e681a36e4bd59cedddbf0ebaf1c2214a5d70e8ed874cd5479e7556e8f91e4be2d703d5e446dfc1fa89d5d837eb275663ff265c87f5c9b5ec69bd9aef68cb9adf8caf3fae33d747047ec2d75eaca3a0f112fe64e395fb4baed370d078057e1bfbaf373b39ef92759a3ebf66a9cbb076ce38effed18d94ead3e1d3d7fbeaef9873f1251f1c8075596ba28135871958a38b81692d0d4c81a332650de7dc667806c78bd13afdcb020bf73209842936118eba0686f446baabf3c0963d0af4c7685efbae2f57eabfadb5aa5c6f1375b6becd3d286e47edf02755cde84d61d82ea68063a2f4003670f7e1eac6d1bfe88f66fa5df1f96e578703df6ce03335c5fb015327d442b7717d0c5f07e0335503baa27f3bfa7d703dd556ef072f2aa8b814d56a1fc9e30e47fb11f4495ee9ae4c65e5662cf866e2b961e0234e54011fbd6d27e06b0a7c9d80af03f0d14c29efbc900a0ff78fc47bc4f0992765ee24c787163a2074627d2d8934fa7ebfaa73de53aac1a9cd668fd75f76f6e4f1456bb04e426464a6f5b22f6e46640c4b1a1429938b3ebd214936f9bb62c4095a18cf856d87eac0b892c6058d6fcfa8a3bfd0491f759f32448f2ff58dd49ef7df161d5b8b669ae0591fd17a404dee91b09da146b75ec7a8814f5e785091d27aea84fb6df45932c177cba4f5eaabf94df88a701df934d6c175a6df83d79b771d058cd742cd7e9564bc8c8ff717fa7d766cbc711611acd35d23415b2badba692ddc9a2db59a1c75a6526df38f742e7d4da903b6b6fdcf2f8d959aee7c3ff44f387db0aa8b522b916deb1903391b32358a8807c9f3852314ecccc8b7a7ed25048408076f383a2034a776d71b03e7dfad45c69473d256bfb0c188e42197f796222de9fc5192551f70fd8035c35c87855318647b80086c4304865fbaa6fe51c1d29ae253e598bff7205d3089f401b6873e166aabab6812ee043699305e7eac075f4c34cff08c7b2497ae9d82f708c7bf07eb8c7d3699009df94861dc97aa03a9ea504215219d120a770d2189aab8f4939a3cdb6245a69eb9d1151fce1b0e0e8f0f875cc0020302dd7bdf15b8a9985707effd3bddc20648d5ab9bb9e0aafe8f0c6c74817eadfa873c3a7cb3be666668f529efab7895615ef4e22c43f6f4d73d241e2b3312f4bda5b139f6fd73cd75acea01fe242a2e52a15a02bf5c5f36f0fb55509909c72b55b201ebdfa95fd5c4ad1d5ef665c95b6b3421dd7adba6d396680e7d53ceda110bde50aa746151e3959a23af9c59317bcb1dfafa6b9c196e6126eb736b7ff7bcb06aa70c4cff207a86e446d747d88c6fb7a9b8d0ace3ad9a35ced0f4f2f203569ca319df36fd8f7c60712ba5263f3beaad82025c43e75c8617fab265cb759a8bfb07a21f062cd8f9716fbb59bbfb013bd96c037c711a2ee1683af0bc871f76a58fd4c60f3d1ce5b448b318c1bfa69fc307bf39e8fbf8bc3f22789ab91eb6072b99df3b0e7e2b76f00fc558c39e5163215a7d026c0ffeb88d2077601bff9a71260ba4ea6e3849cd9d780f7ee115e6ccaabaccdd90eb87fe79c8cc864aadbdffcfe68bae526acda0a5c3ff68add4ea17ffe8b57a8de6a41eaaf9a4ab02aa734b83a1b58f566affd7db4e3ee86a7d70dfd8b2fdbf062bb54fc3c60ddbb5d3dfa379ca996ec9d5a4de31dde1b63c5446d4ef5c5b76c182579fd1b2e673adaefbf89dc5e637aeb8478593088a8a87be825522f7d04e7bc3000fbf71c4009770fcdfd17d521bbea454cb21ad7f1ddd595ff366e8f9c30e57c1713a63b15ec25c02d936d761ddc6d6b19721925e81e85b7d183fed8b6daed7eac61559b140432f0321f1c7dc7573dcacb745ef6f6a5ea80fc4e55f2e7a69b2e6c47f7de98733a6d6536aca41dfdc5290a7bfc5ad55abd84d5606f8496fa6480c663cd861647d2d9b1fd7bbdb7f0e5fa754bb538efefc0c2db9d679b941fdb6cbf5b778c03a3e5a386a17bb03fbda58d5d775fb5d7cc3ac7e776e51eae5336f3eea8b4de64fa5a2a433ad5b99769f0b49492fae3de65df87725206103a4ea216a146ff2ced737acd422fd41e9435efe4599051de524e48296073f1f5c66830c95077000a71cecf76e8e83ee4680d4ff7a321225c087bf061efc7410903b305ae28da982dc13e5b8c5bc946e28deb24673d4f3ea4c0c0dd784e0fbe683bff9596fa0d5d72f7d6333158612f53d387d3b6a8d5396504a6fedb6167d5bd7ab7b8e52e7bcf2df3f4f3f5da956cb3bac38ab9652e9e7d6287439eaa407e02edaa0ce994e5d371071d8b503be385faf8fb1e3f31f5908555409d2c9134129439c0913124adf4f8404f1249c057567736e897202ae31f5dc26b74c724b1db71b74ecac51c7baf310fae9c48a040c90747725c9776e124662bbddc1b7bdbeaa1b572423c683189f8ac165cf6dbc4da985d7ce58f055b152931e1ff1cdc4a795fa6df5d4f6ab90ec4406e8518132ae8f416eda14f7438444e654132d9e31dd2f2da37bdd7e4a759df7df534f0e6909e19e8ebf5ca8bf7bdaf1351a377a396e3e6cf1fe3bd99cb39c7a6e05ced923279c7ce3c74abd73fb031b23f81b5522a4daf55cd256961afecb08c9df558595678075b58121bdb16ebbf9cd87ceeba53fe8313526bcfd968abaf5b97f67cec812aaa23c293140273b4091c410d589c689dede833f99aa882410c6b773aa22bd308d57978c1cdf5e5591e58d1c77d63ac32af5425bb4f59716233447fd66e3bbafed7fb752d3fb8c3ee237bd708bbedc34b518151a99c381f1984bcca25f8eaaec1528454b2537ddeb378f5957563c52a9a95bbf7d7c96e6a826ffe7ebefbed2a4b0ed9d47ffeaa67ea997d6e08ab6e3310f99712a8e4ce1d5b593eec0d642abcc5561367ffee04f9b0cd704e48921bf4532ccdf9c568057011600ca248f74e05056541c48568f1d1991f2d999dcecb919a587eeefd68fc97eb1fb231fd5d0bffdc76a71da872ace6b891816cc03ab8cb08e07324364bebf543d92043250ee0be0cf11f8c672df327d1fe1b0d1033ee10e2cc7db83fbe6793d0cbeaaa72af34a4a94fafd8c19ab877da1d4bbff7d70547f2d234fbef8ab4db3f58e5c5bb4a2ffe697cc83b9c4eb5b80587f65afa30fa373199548461d8d72147a2ba3f5faa0171fc337013521da52b5614e895eafd35f1a3d7cde7e9a905df8d58523f4789a576436700309eb7769bae4e0befa2cda907242ad1be3e62373e70889b5c02a73d741d34ff77ff5d4a57a9fdcd430ebe71b949afbddcf43d7ac35d7500550525d39229e890904fd9e011801cc15fd5dd6fe6e1248c400aee075b35237747b3ebfcd377a6237363a61d299fac7bbadd16e52c26d04fc4989c136d7414240dc86255545317c36ee4ec68199fbbb5b9068a80c545289c106be3eb8cef31ebe1c41313ffd3e786ed833ee0055515593aacfcaba2935eadc7787f4bb47a909977d3e7c3e361e979a254e9b2ad1d1ef540f850a3f550a48e9d9856e96393a8c9c0b6dfda8d48513ee687d8216cd8f59dae53f7777d2bf2d4d9d58bb9f0a5425ee74c4fb18157109c1f7bd06e75ead8fb8e127bf9e311df51a88a32b46019f12a4d12f433d06aa155e81b4e795548f4170b6d59644220690249d728896a47f7a77c8bd5a024a599f7afc238f6c53d20d9b5f452068966138b4bc9a4cf235f8aa8d9fefc377f1ae2f9f4a96f0fb23c84dbf8feeeb795bfee7c21a63341c76efab5b3f5daffb072e6cbcfe7083992bf15124b7286d2cd723d50ce7f54b017bb2467eb28c0311037c9549e3d66d14ea03bec109cd9ad49ea8d4d5573e3ae1cac54ab5dcd26659f7598a3520bb4a82aea85f3ee68f3fb424b2f48153bacf566a9e3de9df2b5698bf95922a966aa6a3e473b9a8f4292b17d2fbeffa54297f17021236800f20fdff13979edf387d9852c7adec963e417314d69fd6931d37051f983e559114356163d0c73d490c73e39f99f4e0f7e3b381af0ff04580af7a07bf24803652a3f44132c5edddf842b73de3a631cdf2ee52ea93c6cfdd3b1aaa18b92159c280ae953938ba4e88ca95e00cf94015aa81f8f89b28c406e492c07a639ef5cd75271fae0f9070db8b173ea32593d0d050abf474153bb0923306dbd5b65ebfe9a969cf2af550dd6e5fdd081b4411fc758aef01446d71d2359752adf0190656a07ec3769776b50de075ad19a2ff1df97a8dec0b94aa19aab5e05b577576b26523550e1152dcc5eb2c12fd5dda32068070f4c43af6ad273ee83df892aab8c2162490c07d66630e128e57e29f7ac2b757bff186261ca7f55f376e9cb9900e7c5e8fb40e2149706df072efdfe977b20d708964590a99321088e49c7c70d29b813521776e82b2c22895aaa512c22ebca2cb83a373f4fd879f9c73c15dc7e87b4f0dadaf556bd71192ad6f6dec3646afaf87e69cbbe946d42d625b1e6c24bc4e69de683ea87225a9fe0252faec7cfb9ba8b0d8cfc136c03d80ce2feca52ef9440ff1fd94e76f724bae5ae200cef32de88ce8ef41816d8510e46c480c0385aa282f89c420039cc83bc5a72a403f2f89c4205566851489ee8bf40e1b7c811c690ef045c7bdbed39fb9bf36d21ccca2fb8ffad02deeff917ab13cddcc2b198bcbc169978283296d6e600912c2970212675e8af8891294462dbd1678a02220dd6c192a0c92caabe20a402ac1aa39a30583a62d5ef9b352878ee8bcb4566da5eaded1b0ede1876f635ee43c14729855a6aa464b9f5aa37373fd9e15b795678ed7846cf107bf46d6a1146c15545a6484ad5a642097ee251b086ac13b19401a01b4459f9a19b92710f09c277afe5a477fd97d7bb71a35da55c9acb316357851c5af337a2fb96e131ff4d99040a6601dcb08f2c21d8c201f8bb7f207d6e6e19dcdfd03b71d41be6ac592d1131e53eafd5bfb8efd0405ca985090ea098480243eb249955c6a2011f492fd005f33b018925ce9ebdeeb48b55586380a7696c0f398415ae01d47051dc02875c00c962050f112f82fbffff0de6237a5c980e2d77f7a422fc68f0f7dc7cdca9d7246ea0d510dc94e7a19a61f59f3d24c4dca67341d73d5fb7add6efd65e3c072a8dc58d5da4af4096600c2898409461e60c1ce8c2cbefdd504c436c08224c4a947b42879e2fee79dfb8a1bc179acbafe40d7b81b5be019d18b3244aa0d69632814077f3efce357b3ea2a027c7400dbc0670881d4394b5b493e0efad56a35aeeb0e7c99786ed8e0f3b93ddac0e77d8f58a4f714e033f7c7085806f0e5019fe760a9a85976ece62395fae0fc479feba739fb4d83d7debc152572cb5a0362a3968280d0c62cc5c62cc1062e25633371e42030c4f1947d0e482234085305e99c4972a11c5504e3921f6e18b47aeba29a9a839b179e79be6b343e3e5437bdad4ae40e6ae62933e080ada6ada466699d92f5d395faf9cbe1c3676ec43840302a1188286bb257de803e15bea20d2b39b93cf130f4793deb1575d629d72fb84413e6d0b89443aecc56c111d362ddb2243110fa8230f74d1c43f700062876d0db1815182069cba075c6712079e87b18131e6fe1b619acdf3bcd48fd5c33046f1f73ffddefbb9cfbbbaa8a0f6c405a37ec6d4484830806312eb42e014bc1c0903344d97c014108ca6003619b1d313242455bf196f89d246d6133a93c0050a8ca5cdb44e1cb733e5fffa9668cde9fb6efb7fabee346749d77c5026518da4cb5d336bdd677776ce1aa84c7f7fbfc9529887be375482a557272c13a261b1fdb4cc2e2f70cc0c88e8c28befd5591e8941597bc5222068634cf7ecb3bafaebee61cdd39441d7ae227d1c931db35e2845de0b447e4e810f4c3c647c6b91011d14191b8dd9d6b70dd71c087c8718af4c6f5b148effe5e7c88aced8dc86fc493687ca79bebccf5848fc6ed0445bc3b1cf11e06be2ef1f835368a1c0f035f6fe0a37930be4139ceab6e65bfc8531f7dfaca10a59655fd36721d365cd9930612612846a9dc22d468dfbad5c0cd58685bde411f46bb2dc3011168b7159ce1d677bdf713a1da32d97bfd162cf42d5bfdf8e776fdf9a56573f4c61b3cf5babeb7e81f5f71aadcc0285f44bdcd11efd17e60c4fb52fdbf6db4fdfe9571f0197a83d568576b582dc477d4a801888324fd7103d31e3530a591811c094c56ae382faa68a38262367e27abc4214a9ddae4caffd63c4ae3b825f58ffb3b2ace701018312dd6adb20322b29109212ee3c185b8cfec83ee02ff106f4436e3ef2ff1f3bef0e08bed0bef3eab6a52f953e5794acd6c1ab9e25dfd5ddfefdab7db276ea4ff494e791924d3122419245521af3fac9bcd38f868dd31440a90cd20f4bc4eefc2fd19c057e4c55bdc03f019ef7319c206567437200ee6a25c2fdead5827bc9eef0c1eef9203e70efb73b452f35e987865ef889ea78bab3e2b3d28b65f7734e27ddf9456196eaeb32bda3f38258cdf6ae3b9357f3790322ea483b14b23953145b2938d87322e5060ec4ed7b0ffab24102ad94a91e4fa052f19727faba65b94aadfbfe9db23dc83a797ba3bfd9aa8aed71b28950f01ac2b07ce450f6e6b2422519b627a6c4496f6c176ce52e746fb03ac6bcc7588d4a52cb85d832265a122202fae3ee03bb3a0721a600e7e7dd56a8ccf5c5f2802b2a67823c735be02e0cb00be289f630dc5676d2a22c70bf1dea4aa9b622270d71cf3c7d953f2941a3af4d99787c36ba87c8281a53f195832c8c06214f72fc6bc17a3c6753172f41443075cbacc40524995d507bcc340e6d848558583b61235b82b7f01444d743676fe6c60552dc0364a4d2b1cfde6224d584e9a77fe39c7acd28b7f6cfa99fbbb78fb307f5f807930f31414f17e9c8a92376b0d6f0f0fc797b23c35a59eded035fad61ee79efff35e9af8c3f20f310e4818aca280a4547996b7cf7121385898a32386080717b99f87862a754ef39e993df503439d530a2e7b38ba5e282ec7acb37e14318d754a190d060644785304f9ed58c773185f7fdc47fbc01b91ddd51b91cdf89bfaf09bbfe71b7c7add25de174d745f73c0d30b472f786ba652c3faf69f301611d5a412225512312ec590208a0ff1fe5e04425c82f92b012b504292c5fb80b42ec90b0b35ded9f9e348032bc138f13a942a28591e0011e19535c5fd483d52b9c97b3d49a695641b834dd075739fb6e9bb977ed7077cd32d07b499afc7bb5f8dccbbbbb859a2af52ff87837cbb22dead19d6b2d0251a5fc3fd5b1ca925e79fbf1f71f5679ad1297bbcf8d5ca2fcd35ce99804f611c2499d40624f7deb3bcd0ba7b5b4fae4edbd304c43680371a168e1bca9fd3e3f2c9f71c1755651c78ca23d183c190194add413add0c615c1ce8335a1bec8542053505a276368c7f6b025505f4414d9f5450854205350509304817bd06c748863062c6540819c097077c5eddf6148e1cef67ded7abe28a534944802fda9fdce2ab8f3fd01c73c1c8598bc95b83dc134bf17dc958cc711001360ef23b972a804a703a643cafc2c265ff7bf27e81ce9503bbe877481eec3e4b07af79b368ca86c337872fafa3dfbc5eed866961330f799887c4aa14a9fa198803b829ab6acc3cc90dda4ebdb55a4b6a135f1ab1744643f17e7440e0e0280701a434f1bef78384c549ee32d01fa8d4c92bfe2fada626e8cd171c74f4604dd0adc5eae87a87a96da83aa5bbae2fc27b2cae33fd42a4e6b0814faab8f2808fddd871ff40815fd812797d06a9b8b02ffef8e8b795df2ed082cd374fbf341c3c35db384855059569111815b661d07aa4f507e330a9b0c81b8e6d16a42225a3bb5425617d914a92fa52e5e88364337857dc87dfd918bfd8db27b75a5621d1df81d73dd77eadfcf197657a5f1e9a7ed2bdeedfebdedaf0944ecd12a8d6e97b2649f1136a98b2c1adefd2b269ebc6abb5a435a5ff372fcdc7bef515b27a578c5fb8fffa9c3f720123db1a41c2516def0d3bd9c280b601aeede3d497af3aa3f624371a37e5b29b5ca138623e2f275b8b18ef662dda9bbbc7c0dbd9367d279b974314ab1619b3715dc4dccff8cc53f3595560fa6370bd6dae8fe1431f2a288daf37f099e75e88b0b07c88fa0e9e3706d793ea25dba1b71e037cdef788e1ebeee93bf8fb185c6fe37ee0734ead3add354a4fedf1ed01bf81d3abc482218e8c3620e998894094d2c6a5dfb171c9b8eef3d612de32e4e5213939f93b491ed2ab860e84b236b1f1fcba6cdccddf552498976cef3cd0f7d5f360e33aeff795f3dcdbeb6c5cefcc065f1e88832295bcc4c8bb06de3629a700c2d84e2a00cea23a36004600f5baee70c8095d2f7725b886aaa2c5e5d1f119956304ebcae175dadbfb5ebcce8cea13aa4e5a574e2cd9a7c127d76d84d7ad07bfde2f89f187197f18f7d9e87bf1017fc594b2269b6f57ead3675ff8231f9204af0f923c28821a360e22144c384812811b7531181bf682fbda8b870908d924681d3ee4855501859c92c14a799face3216c22bcafc896739f78dfb880d5813d7b5ff4ae66982a9cf26e2baef79f3b4ed877ee6cb3658ce890eea68fb736841ea8010d433a9c64d2a07948850a96d633953be0e4a116908505dceeb6a70848d8005f1a63bdf1da743ceafa735c9bc7bdce870dce8beafa23d13fe6fb0e608f0d20688113e1f06dc87cb66d40c5e1fd8071f8e8b944383c07121f6844382ef4967d71c2b81e3afc0404d06bcba071e78300127e98be9cb0d7564207e6d6a337375db244a9cd75d6e6916e970f6e3ab0c9ed91bca428ce81bcb1be155046b88a8d042d79cc2d50787f70c4bae0882a094a82029597bb2147b77d7fd992abf53d7f547de21e5071071de6218031c8e6f502428e79a20d2a0ed89a7dea3ed3021216b969b2dbe629dedf69e35962e3791dab63d00ac5ae0bdd9c72e19557c6addf7cb34e785df9d6b3785fff3af0ae2b1bf87a07ae5bef3aeb2df03b9230739ff685171ff0ff366cdac5c38e526ae3b9ab3f2a426024ad17f6c6c3fa222f3f22204438a43b2a7b61915306b9ef0232c1a0f588a3d657bb5c014a092309a4efc7c668405eb7a2e2a06f9f4982124710d7fcf78f8e9bf47a5e7ad2dcfb5f7831363a870877f0f7c3f7f7b6f4949a8bf6d71272b78b6efcace306fc06c291960638de406688683d932d4f9ec339de79a87edbc30484250f827ae02975d39a5deeaa4ae860204e2996fedccb710651ee086f98ea490cd9019c1d6df8884f6290f8ba039f314afa2506410069dc011c1e73a8c0cf1c2aaeb7bd0766c9775b8e5d0d5d3b2f74e29870509743c72f37b8f4b7e7d41dc489112442404799024cb6216df4e9bede5ebccc391201f92e36aecaf5e567ba49e6f43cd8e67d933006c449b304b26dc6206540ca43758c1521162846101b8ce302c8f848128694402ceffbbafddc471efbf2a0f7f47f7f66159d70a28aaddff6db96a8e3181471d0f33a30d7cbfd21d759d0bab5057e264c5efc8e9048085fe996e25fd7e81d34f2aad7978e16de75c49933a322e269386e81240bf2e6a380385a8fa2d224c77708ef385faa124130e479930c26252c63c43868fd0a0985256bbc0f4b54fafd5fbffcae8bbee8a5ffbb53c9e639ee97a3f94ef6fd025ad665c73f76066c364438d24f479f080849d630aa33432419215bc06ab73d444038b2dcc60f7ae0ff19786b59e3c67a086f875e3e6d5c8283df262f10c17186bd077f1ce50ee3fec41b32dfd4dbf0a98ac2e2e0f7e1f31efc3e89e142ce94047ce2e0979c72108717e350b11d02541138302b0fab7881381f5ed82232970f68caa123fddbbff35eef13f189070ae30d2181547b434a4985f090919a601c47e76439cfb91baeda8c0171ea73aac71884ce4dbdb8168cf84c2088609c22fab0154909440608c6ab06ea0e69f8e1c5cdf4f3729c68481e7f771e1fcf02adab30c68bf715eb4cac03de0fbc3f707fb275db5be077121366494808df6f1d271ffde51d9a7119bcf5675285922d82545714195d2adc7439829a6c6c227095dd67b11e39923adb0b791d4a421151bbb6d9dee7480987f6054bd8224343b9c8ade612ca8ab7cb5bbb9258c1f1b346bdd8c8238184a330e8fb0548248ddaef777858afbf9aa3ea8cae09e7149640004995c51236ad6b4948f0be2c8954bbed6e0212167d22247ae0fbe6b652e1ded1859b937a9af21ffcbd213148ddad14e9934b0c36f099fe1ca12af26f181bf70571b211830f84638e38f8fd9c7244e04bc8e1313ebf4aaeb7675e306e6774551a1104aaf92d0fe440af932aeff5b2e83f46e613edb9804d759bb89f555df49cb8b8108697a8d9d1852d3794cfb6216c25edb1ed831903d3bf4cbd4ea2bd45ba61824410481221b7dd20c923ec85eecfd63ed69da7a62a1fc1675527ad03c7c75044f0be5ec2e9f86c19065f6fe0b3036c4272ddfa6d7c0909b364809cb4aa9aae0a73c215c3f22691571ad61b4bb6a4c221098402048354a622b29c0907312e42a2e0f54323dfd32d2c9e2ffa4ce884244f048425134d5887b67feea748445f7b61e58d9b7ab9124892ef1770aea58c4f5d52af9e52279f7ee9891d5619fc8922e6a3d712630442224bebfa92058513ce4282b6a708886d403cc796124e6f1276ff1e2c721b892189eed67fd004705e36faed85aa2899c42074961ca7413ae8f6e2e00f9018e238633c3740a72d74ce71f3e239306b0eafd3ac314548d34623ce883622b2e77a0e68e5cf19c4f7670b483c8fad76aed1fd11c08003c21d57a867ca93fbb9018ec96c48ac92c168e7409518cc1898fb7f549d6958216268089e2c7e879138d0681ec7109d74f88517d47a5a774684ba1d7bac9fe0fb54a7ca67c4f67ef76cf1be31c6cae00b92d08325302ffe00159a648036e5af7d7bee5ca5d6a42eddb889dc59c996859964c201c9830908491a4438a4c421555401eb62b7491adbdbf0fc404282f1cadc5e2c91e8f75fbf70e58b6e2a9de22bb73c3eda7dff64df4fdaf48426a4f5f48ec38e42bc4cda69064a02c292086c213e9b9e90acff3604c49294cdc6ef7ac0564f2b3fdb51db10b9abadbb355803383bd61153e0949418fc2a02efc1ef0889c11612c31c71f007480c719cb1c0276d3e42b20a30bad79a5d77c6fe70b365ed3f71f6b4a08788df09d2060d63066cef7dbc5109ee6c8b88e7d3f3bac7c673d8f3d94fb8de24d689d6fe51afa56436a4de4222a4c0ca648cc149ce0f3cae3802108524c20b49434a1c52127161db099d1a1cefaa6a1e721e720b07c5a98ccc78a4ead44fe8bcdfddcf4078f7436fe0b305839244028b93e812e277c22ce144fb7f7cffdbd39310a0c792ab3022b37712110ab26d947baf9312b12f0d7b10e1f8bbb58801bc5f6c6f9f35024448a4d15d1394b5f5ff78db4d5fef24fb7e496c7a8dbb36afd71199154855e5231c9040c8d6e7b3e9d1391d16fda46d4fd940e236da11b79ed2b1c613bae3580bdbb846de40919b8ccd4215954c55e49718c2069f5189f92406bf8a200c2cf401c3f837b1c4208da30112431c01b43de3669db6cf98461bdaf6cc0bc69df24ada61f5672875f0594774776d499e16069c1d3f23ca4f18007dc9e6226af7348937ce1faecbdcdc338f776d1f396a4cd436d17bdb8c81f4ae8aa926036c4834cf3fa893e8f13e49428af6542ad416bf87c5ef7a5da716d4d81a2da11ca4328a79d9c983c2cb5044844a23c8966133a3e55d678ecf2d97f079f1fbdc4979bf918413bd7ec66763eace6860de93549e32b961b928cc452a2ab6bd05481c3ed5540430acf68e1631404a2444109940d2bcc5b9c78fb8fecda3c6e8fb9d39cee212d7bd599e13f4fd82dcb8f13d6b85eb763808019ca94428c8e6417d481e6cfb206f2ccbfb1edb9f0672771110db0be3b35e1edef594d5ae88af272cfa628e4c11c2a93fb84f0bdef02732450871febd59e4a3dfc3660cb8bf3d19abc575b1e786f17b76003e07f8687c59c0d73e009fe31db7f73d742f5be033d7b1e4e3887951621e0cecb2aac7ffae44ae1e2b02489c051608ab64141aae93dfc7e795b19b1b17a6d2e3a9b1b4f6ff32725deecd09b94654e6cc28b5c91831affeef6ebe476f25e61990f0a92ade263c5fc22b25c8b828090c1bcff5fc8516855a1dff4dc2ef9e641d38def51c4be5e2fdeefef567fad9bef52cf6071b6b3df883d629f5cb6e2a7d71c3ad4a1566cd3e7035b218578a780f361207a9aec8bb0a84c497351707abcf38beb7b588012c81e03d581221c98b547f7a5e1675fb25cd75ef2d7fa56cc4ac2671eb43ac074ee9131646757ce7d0d1a96fd69ba6d43137745977e0bb063f1bd36113a1d43c2c919024229c4868bd57df2b6b4fb9f1da3198767ffa8ad6cb5452375535a79ade507edb83b95fda1ec80b260b7caf9f53a4e54b9c3f9eeb93244c9fbcbab2a04a902aae00e3afcf1b4672a83e7760c1910a91b6fee5cd4e3e567330077d7ef861248910c1a022fd1c0847c6e21fbcd705e940a568bbcb5b87d87f3efad5c53fbcad09e18a7b7e6f7eaee678abdeaedcb2fc031533e6063b2598fe6ccef514bddea7e2a2f5f65ddcf393799d5c24fa76e2cba22ad94bacc1adaf518924611a1fe5f00a47fb3e6f3261bc6609354012cb4fa2e2ca162a34a9d293fb4d792595d21fb6beb70ac659e6a885f3057bf38980be4a59a7830ed63180b4d36cf4817faf6f1140db00270c88f7f505306ac252f95e45ad684a9d00dbde36545ca68f73e2802bda95b6844a9b09c3235e9822e34072c4b8abadbaa2b6bb084838713f7a207da886377c21da8db8ff385295136189c11b0712e40d15e055e213eddb8370f046164671bfedc17bf0cb0f7821fab369c30b1597cf5819a0daa0f7087007f6cd8b50e558abadabdd08d43322d70cb81eb98178c1502435380e1fe7418485088ee0b477dc3f5cb4b0f739d4ac0ee2ba8852af8cbfe5b309a72b35acd5802da7a52b555cb065ca2837f99d3f80903690f9de8231f0a9b8687d9c1c6373f9201bb363ef132ffa3be3d49f6e4df3c008f22ccc62f519212208def725e33b656a0874d715ef2f55be315b5fb667bce8177fb965161390002f3f8ed416ba7e261ce48e4bce1ad9de799307ee3fa505c6a9e0f77842527970f92b7fb409667c7cde867e679c68bf76ee3e87d6ef66f0fadcd3699f13e328dd780318c5e4b690dd44406464230f24a2ffdfc87aa5eeb32ad83d514a0cc9bca102bc4a7cc6f739220e84f8032931f88c974924862c1cfcd59418a4118c251f8a0311fef9810788e0401ad46e36a8b3dec0675e705d8be3906d348544d77102e2772634b4a04842913601fa7ed575e30d0346bc787c7d3be07efdfba4efbfba7afd7aa51e5970d1c33dd728b574c86f115bbf715566d5668fce988c8d823108f46a1a1d934158071f348e8066253242663a6fb9b98a826c67091897c4eb205904b9f4eaf2d90e03bcaefc715684afb767bcd86f1567971d45190ef840146edf4c508860c80054922cc2b81f045b1ea8ffb81601b40de0f7264984243a4d982bc655348de6b08b313ef4fd480209c7f7f91c1212657ab79abd6a2379a2641019d23e972a59a9c2adb62d64777b618983c2ed5bcdd5a6ba261bac38a805a58df9cd4b8e2e0c9cde835fc98d27269cd2c0c754455e7c81c64b9fc4609e4369c467e3e0f7abd01273ca4111ef2c81046c787980080e84f01dee648fb9ef78a50efd39fbdffb23a92245a2728e9c53bd90080d1bdb607cf3796b501a732b09140b91346489dc5f3d7f171c4f3cc7f66ac3db9efef8267dfe37fae0b6cb5a2a55fa7bf1dc052d30032a8e3188cd4b62c6e014e764c61fe0c6cc0740b2c4dbb69ea3d343f3a2f3f3b5da58d78d700f3266fb559d89d781dc0ff2a08f88f7150c852f854e75256ac7eb7d18aa9d3a9e722c51524c9f719822c3a91f14318ef92552c52da2fe99cd4efcb3741a70e72734d46aeb468e3b01818581aa582151a65d57f3813af096234d4248a8ac7dfb4e3a85a8807e60db535e5871ba6667b8dac74d02262506dfc2ce177efd82a34ba02ab20dbe00551179e9c45445369e6b0e7a7fc47bc4834f72b273e0d545f882536d78c61de856198b440f9a9731021f1d5076fcb8adffa64cabf38c52279f7269b8572f97605b1f51ae9cf4c70c247f714e79400405120a1312d2a1caf80882c2586f89bfb32d46afb30e734e5ce91af7ee993be8fd136074256f11a94a936e9155713af6315d060f5eb850a917ac1b9ec81da8d42ab5b4d110378dbd6d948a8e7f9ee9bb19acdfc5bcb0d81be87beff3989090917f1b6ddf469923a34919f5735252e3d69b4cee392489aad36feb0be33a2f23e424b399057af379f0fb23dea96ff0a594a40ea0d418b8d39ff283084a6ff13bedd86cef752ce94504fca7371b30021836c09daf50b7d4171acc543146437c3f474a94010c66ca8b2947a4a19e8db471b0338d545d4986ef6f63030968d101df84823481c911e9a00fe0907654554412c30eaa8a7c9c1db903e7b304b243124360f6e1ed35b60ae372edd7ea571d7f9d52ff6bffea03cf68cef8a0470fcf6b028e9ab27846dda9555c364f4a8120090ad94e3e053c59c0bede3ebb11ea0335f79e470f6ab6af5217be7f47cfe177ea710da957f707bdeeeeebf161bd9b517889236689701141c102c74cb091d635de6e7c6bf51ab7a0d50bf7fff7b867f7516ae9a6f96fbef6a38a9b67b13e22fcbd79c55410611211f17c1052c11d3c5fb6e8c62b51996e12459f842ab3eda2c053e0fa0d625c826c39d54da1932cfbabe46cb1ce422f871e6302922de6c5d9f6ef3edb19416a1101ffa18d096902c923da22ee9e09fdbbd1ccb8ef279c26b61150eb6530573a875be64ebf8a55120a12f9717df5250ed9f63001719b73a953e9be685255114b20011cddf6aa8af285c4b09daa221f6737872b12423591444510b4c18372256dafb135c0ebacf63df51ffdb7beb27b9f3b8b3ffe48a9cbb21f6c71b616756b1e53a77e2d14a2e1b4d0e06098a0484905f50758159600b66f77dcc9356b2875eff20f5ebefa3da55aed97654daead176dba75f9a9711c7acd2db5ef7b7ab1be6ef0fb331faa54aae18cfdbea959d38b8f0809736c58091cb8462922ca947a7551af05795d959a3b64d2b8c7f473aa52aace8f56aa93eb23ce599403dc44723c964c3ef63e97ad7163e2c63551dd10edc7387a8c56304843b0fe8224deed8d200f60841c29010bdb6102db9097b3c5f7495f5cb369a35f94b74504b4bd50da92feb1368eeab648403f6c803bd3d67ba1371ab905d9e8fbd9de73414a24b1ef89fe183e1fdfe1e74855f1d8c4cfafb6c4110efac39e222011c0b07ecd9e8ea974964c55149c1bcaf4b7575574a19018765255a425101bf88424c5e3b13de35662dc3eaf336527999788c0e7796ea0d719f085ee4c9dbeef254a65947578b6df14a56e5df1dacfa38e55eafa179ebdedba6b953af3b46b1ecdbac9f58cb2eea6e46c3ec2d2d1c03452856989e5daf14fe71e32541382e68316dcb5454b1a23efdc34e33ffade4b6a5ef6eac5faa20daa5f8b0509086077f5b0f58952b57eabbbf80e7ddfcddfbefcea174728755adb2b27646418fc6ca379247e06e38cb838f029f2d9cdbd34a8a1fdf897472bf5c519fdcfeea1f194d85b87ccbd286e5e4e5227d0d1cab98a449c027b191101210e1bf771b3f56f673a515f3287e27afc9c22492059f1fd9d8e20af3e23d43b1e9fe3b70d79c78bfd5763609d06075ea554dd760d66d7385d256e610145dbfee47cff9f34db0097910e2d0aed9f9119f7fd64260c29a106e5505bed4ce5cc0ab6f739b46f7c0405cd2791c8160e7a913de4c6ebb1faf757d1c2ab811c17896c1439bebd5959835445f94262d85955d11caec54ec64cafc4106cfc4a7c80ec2eafb3800324f476ea0cf78068b2aae5570f684ebce331a7b51e3d5a13821b3e5835f559a5ee5e36e8fccf6ed5b0c17b470dba5aa97bf61f74e23b9ab0dcf7ebe0d3bfd39cff83ed3f2e9bff9a52cd4765f69bac39ffb4f76bcdecfba3722bdc8d3a68d0361803e27845e478ea88b4ab8ee9a4d489adce3bf5eb12a5aee9f2e481ddce3133215332d00620632d491214c0e6d69b987cf857372f6aa5d433b3af29baee0fa556b658f2e77b99ee1f9de3495545d961298b2ca71327027201be84e3851ecef27de7e1e8fa664982be8b773d680964db043fc03dd3a7ea7498714119017a5eb519212f3ec9d9a26fdd6fddefaa140fc9fbf78083969a2b2cbcb7cf3946e8d4abad1a49f6f7bdbcf95284c44906976ebc7fc97eafebff3e2b54b3bd5b2297be5f6c1fd3f7ab9e44a9544c0209b0552675970e57efbd626d4fc581c435bde04d8a3a108ad8c16cfabe485b8ea0c5f5d9c2c8e888eb6291ca38b8189f377790c3d7399e71385e4ec09191cf8c4f65019f39a81d7140cae7c4c647e3cef6cc837c8fd8f8685eb23df320df37763f5dd75ecc73e2f71011efd68a508d7df7d587f680b48b5c63775a56fa88b326ebfe55e9ff3bff7c7d88df90727027d7bdf302ebf3e697c573de81efebf97e32125b7e37f580fa639fe7953af084762fbd3c4bbff67f3fbb6a66032de99cf6e484eea8494eb61ab2b900334b1454b8c84d5a57d466d34d1b8729f562ee0d573fdb4da987ac6ef54f82cda308b5cd8ba8521edc56b9a4aa2028e46de4310e77b5bae27d6ceffb7823c8b504e29d7fff3acc16df29db834f46906751b2d1c075b06dfc0e7bf978f0cbef71f0811dcf391139add8cd1be706a707c7c1c801aa32608d088c99a15da07bdfbb9acf6d3da254eb9e1defbeb6b5fb9b13553925fb7ef29c60233b9d5b4d9cf4406f2a40291132c15789ff9ebcfd05361035ce69eb524827a6ca21ce9f16b2a1bc417eee7eddad97f30aca0d4491e3dd252716a022607c01920479c17417712001a266a031940eced94974e422302d59c47b9c7bb113302f633ce30ed4b5621cb37d1c347d37db332f7ea78488c067ee1be2fdbe41f36ccdb71ad4d647f4019ddbad7afc27a5eeba3d6fcad36729d5eaccac99f5a71bcc64c4a7c871527171ae262af0739fc6fbb17330153ae21adca40213751c2a6103e08038e20169e5b97d1021bf6a3540e519a0e2daee08f25841a96daedf40c95a79f153c4bb23545c8d6f6a7e44e76f95aaf57dbde135a0caf4c5179ce2ed4b2f3c3ea8a4ce3dacfe99cd060c7b61bc113bb54eda9453b5c4ee24dbc722c9a54fc5458ceb3dce8d5638603cf2f7a0ebb6bbfd1546f42aa18292221b2d6c7fa9583351a4e2aaee4654c2ab2be64ee93d30a58a20b9178ce1f08778e340020f4cbff192c66dde83031203545cbce1c5c11fe4069ae535ee27cb6aec4b99210b606579239f39995fb08d27e14267154d775f4a19c918780f4210c0baf51b2c3bbbae52570ee85336b4835267bf7263e611879b1b3820d2dcc111d09c0d952ae751b658cae1244aa99271be7230f0887a296c047567e05bab962b89c40efa00e3f81ca45a0950716d7704b92d9c2e02d6af13e4841140f0e5ba0ae5a60edfe75cfdca0b2e69dd190499250d221c7dbd9024134eda8769f37903fd536d24612f8c271c3ddbbf38a25d3bfddf2d42758ee8a5e2bcacbc1a0635461acb03545c247fbf1b53614942e2cb00b1cbe6fdaf9040945ae9fe938093357de985b59da562b72131187c31774a1bcfdde6c11f687b20afaeeee2e097de50e2e08f335e7a0fc8d9d0698b0513ac230fe0745962f0e65e4a5691cee7c61cf112eeb848ea88171fcf4bf5188318beacf87ed21af28231487d2fed8f03ae54ea983bba341d74b05257f47b78fca9a79a275160241d681caf40c6774a6a4715f5446956999a8303e412a4e4b086a82b3ce30c8bef4fdf4f38353852b21611c881363f9a87dec2e92228075790e41e90be3d88a1387068d6e0b310e94c39957c258101397e8824122228749062a47cd0daea1fd582926fba04a4f165fbdf75bf6b7b8b387dddf9915e57beefe767a4bceb8af6f1db9a8450135e58bbaffd151288e3ec1bfd8fd886b0a3bffb7243f90e603a686c73dd76aa8ac86ba5faaaa230f0790f7e123163f86ce00b039ff7e00f2e8065c78f5b73f8e80b955cb650150573ba112f3e6feea504f31211f80421f78e3b4112cade09e7253901b4812fd93cd3c6f1be87e4d08f57f7a78e57aa75f38ecdfa7552eaeaa18f7ffe1fa8b652e96003a74c1b99664012145f52c08f701dae270984655b9ac9eabc77b292bb3102ea9dd720e3b82df0f9253d2ffe18e392f83bd9dca77de961286a75a8bb7f3bcdfa753af8ac3fff8579a1b81de9ce4dbf73a0a89438e860b3f1fb6e3fe8f6500b03da0610a174dffb16eb95473aacd673f25dca63e7bf14cf0026f97e52a20c92fcef756aec799560caee41eb8b802491577322471c78ca2ab7187ce8e894eb8f3a2a3ac9615c6c9659d8f4ad81aa28da6f6a38737d5d66b45f88ebc3e67a8bfa19c644a7afcb00be3ce0cb31f880bf03e1b3fa015f06f0e5015f0ef045802f07f86ce0eb017c3d81af27f045802f07f86ce0eb61f0619cb6790ffd7e346ef31e882b519dcc7bc7e605ef4df39287f7c8e17930cf198bf7c8c07bcc51b9069f35c58b8fdf2303f8f2808fc61d013e9a071bf82e02be3c312f11e0cb013e1bf87a78c63d16ef8179d0f83281cfc6bcf4f0cc4b18f394877e8e581f63715f06de639c15496dae5403d5f4a253b424724c9b335a1e788052cbd6cf9f3371a2521b37acd958f646f40e9f5755d581808b0089b0a0067cd59706aa3c40f3c6d1755ef7a0861fb86ecd6d271cb3efbdf746dfdb4af8de5966bde8af81f520d657a1585fb1f7eb81ebcc3c58c06f03df409a67e0abeefa95dfc906fe42c69f07fc9e75d1ecb1569fb53d4da95f52239f7d3d4fcfd18f15fdcb903287eb7e1041fe7fec7d77605455d6f87d93425540042c28a189065054c4b5918958f613bb045d154d5c5c0bbbbaea5ad6c68bbaeaeaea2a2aabd8829505549a28b6bc8080080a0a845e8288945002a46732bffbe69e73dedcf3e6e64d4050bfdf77ffc8cd9d7973deb9f5f4735175a864348f005fab8f23d561a8d78adf66295055e80da84b54ed3230e76ecb7be1993e723c3787b6f61c183b2fd4d316db777cfe2cd8c7b80f6d687786f9136afdeff8dbe62317970bf1ed639f7df15d1bf505bf0992bc14ab544d715018ff84296bc059c4372f0eeff02f2181dc141d19fba790a98ab298aac8f37377d4733e4e595715906ac7a02a1a047ef84c5514ec4e6950150d82f6deaa8ad0c633489718a261c66927ebc6cc6d48c973a20c9ec186e48d3383a7ab128d1203aa4e32992a918bf2ceded9905a766c7dc405170a71ed930f6f1adf4b880b3bdd7ce771db558f30309238659eaa4561e41547242e71cf45fd2a23bddf5e6a9ec4ebcb6783e2b60c068f3851834a2350d5c9e6c946fc0d363380df24bfd9135dd70b7151cead17e7a8882ee31ddc741737aab2186349e31c861adbbfb5e2a88abbcdbafdbea3dfab3767c9110e3d9bb2f4d26745431a06d5e6b642de3648fee2b53815d67e2bbf800472dca6018b410299091248624e761e719c4a62f0382613a7acda7e8e2b36ad526250ed9ed036490c45206023a7ec001e16937c4683c4d0d30278d02e619c32b63d7836c0d3fb313a5062c806780ec053bfb7e9f738ead88f61008f8f8ba3c1f3c6355fc3bb484fb5469c743f92f4f2138e4bb0c4a0de5b0cdff72389908fb30df0b2019e8e77913e0e12de48803710e0c5be0fb508ddd9ea62210efba86b8f4b24679679e5296595770931f7fb8f972f9ca43a0882882791a08aeb55f87cb3fe3d969804d2abcdad693f4a0964665f9040988457049c66969a5f39bbbd00efb0d66f2e591741db2459dbe2bc587334c033ac37b93e70bd227c05af00d65b364980198047676887e1779da1bb1abe2d67b769d3ab54888af3777570e4139be7942cdbfe817a30b24ad5751da106db52fd35aa26d604254138fa7e73467547553c49618a9440869ef9cf9423d708d1b6eed0cfa62e96df75b386b839ea1248946a7c69fe98a4ee804408eb5fce961aa5ceba4459f68fcde58be57bbeddf4d982ffdd12c80b9003354862c01bff7cc9e07e5e89419892cb9923de7589617192eec63c4d370ff4da575e677b2b3170afb3e00b9e1a9618b80d29c8f81c0ef03a1334bf0da794b95754baf1236d9f397c4b6eaefa653acb05c6d3de87e03e15ce10696e9ac78add6e1d0dca863b8e05c61a8cd846af35be4f4c81b64101abdeb86af0d10695acdb79b463746c441e34cd3f3e60fe01dfa807f815aa3cb719dd3783840258145f565847fcba8ba32adf55c8727d9c71fba00b9b49d27ec888ce156336ca0fcf1135ed068b04de71060d03cfa1166612a59df87cabdf54ff61a4ee67ef6940f925bcb0268b0bdda51a3547c6dab1b6ef46427e00b383df6c5c56ef4137ca9f4b554491e83f93aa88671ff63676e2033359af336f01da6c5c1c1d5e925e6741aa4454a1e181e71da81c5e725e6704cfa0eaf16ee84b8e31c88eb64542d0e45c5563d2404cd942aa18c8fde54b6b1f7fe09d2e5e8ad5a6f9f218988619224f6554a8f79bef139a271d9e699ff855b4dafa8a32c2170dc8c1157daefe30d7fdf99b73a7f57f44128c39cba6ac5bf50a8c539ca641ab71fcd0cd9aabb2b0c6e71847ff8babb6c2503baaf2a54587feb884f28c8acbce7fb6b5fcecbfd6cebe7db5759c2c83c5d78703ed2cf85661c1ceb7daef6ab250c2082a688bdafbb2af088863fe2ada29dacffdde7777b32f3216efb8c68399080c5fd8c8c13178f01c6e8ca840375e741fd5e179ef55cf7bf8c1ef710275f81e3cc22f0ccf6569cf65b17e107ecc26e0f5177fc7decb36b8cdee4a47424691ca8c73e411c71e7e0a6f9bf00b03bc2c8007e34cf8f171d1da1e7ef49e2cedf7997ab2cc04f3c6c68f71d4a6c8ec2c46c8bd718e3d5fff7c7d6bdcf8787f42f339aa6efab8aa314b715a1f55935b300b94730fbc68b598c4f0e7f3a5f0cc6177e767b1798efad661d4303e0a3e839760ddf0f1373da7e065b175c0c6bffcf4b2a7961f2ac4eb4fdebbf2baae42ccbafc8377173eafc681526730c21062f12029a648769450f8ef385c4e581ca86df1f394b00e8f13b810c75ff6eb8cf0a0b79a4b89e3efe2ed889b2a2774704a6bf79a01fff9a38fafff1c309e177adb3f9f317835732ab7b8297c12159221b138f0f95e1392fd4440349de726a134cadc48c7384d311639e8004e36c9c03684279fc3802e5b3da54b2222d9c036c8ae6a74a7f4738e85002f6c80a71bf793cf6564c7e38dfda0649426151771f48ca331b98112bc00d586cf4fdd2051993868c1545026bf777f64b69d181e53d5f58f7e8e0702651d86fb527ce9ecaf50351d704ce5122320a1fa2bdd83cdb88e094f76a1145f0f5cf5668a8f42c921f8022dd5662acf2857ed390c5fb67e2b9bedea59922bc4fbdf3d5dfa640b2176ff6dfb6d9590fa852ee462358e041622089c60e0418c07f30cfd797e256b8813143e1fecc027c212509bd29d936451c46a89d71f86dd3bbe5d7b29801e7269e64715f2b35353875df19248a4a2c47da69f0f81b9cf683e615e988681a940eb1ea919822978b050f24f07da9c6084d9f38d2628298dfd4172c53701e8d6261742a761bd0fdae2a613ff7d8b2fb333e43363acbbdadc16fb3a1cfb0d1a150792fbae72e7252323b8777aeebbea7932fa817109dcdbc85d6e20180d6d6bbc7a0e36201a154b7437586193fbaf03f0b2019e0df00603bc20774a1be0e5c1736180d719fa1706789d35f816738365c6359f71941b5b4b2c2070308ea399511cdf93ac1b730918a96dd113e015b07171005e36c0b3015e5e3cde16b963f371a179cbd3c6a5841b190d4e0925caa82ce1f5d2c6058e058417e91a79a542cedc8c35ef954dc25425afe975e40855d7bd0335b8a7d6032b4189b373a514734deb12d766d27d52dfbbeebe1b301571eb18ddad6dd66f72d7c5f953c65263bf8b58bffd4e0d6a9cb9bb2eed13b6de4ceee1b96a1e6be657fcfda7a38498b4f5f9618fbe2bc4b697366c2f5b00e3016eba649cc51a23fc0ff7be1f5635f2fec90709d1fbd3334eaeea20c4f799cee38b5d9bc0eafad7d13c4fa94f500586e705aabcf2588d073dfc1e56b02f69a0ec3b0c4992751ec30309c6000faf5bda8ebc3f5bc26d37e5c8e87bf3e4678bad938f9b20bcf92b817d9141fb42b54b02dce44df35744e1081909e18313cd0f672ceb375de2bd7cd1bc37d78e56f852668515aaae394cd564446781b3e8c64e2cb3037598b5a9ec2f0282290de4902c1f33a7748be4642a0acad2c66d11a2c3f0ce151def93dcde92b4944cf728a6380188d3002f1ddf81c90e86b88da90696792b91d74f31c17b12e0213fe3c05f3c301d06cf0678f900cf0678f900cf61f06c80a7be37c7afa836d804242169afe01141e4077f118367033cede017e02f6ee52bafaeb803d8d6c6050f7eee15e6793fd9006f18c0e3e3e2307836c0cbd7decbe357301e269fe62d3fe1b878de68450c9e0df0149eb83ef28931e0e31c7b3ed2ad6e4d453b21befce2bd6d9320db2ee6baaa03af2bcaa1f523b47f82e73022fd7555bb5bba456aab9b52df12a25bffbeb35d0212371e19301e05b1b689c099bcd738431486f9c47ef7032f2c07bcb0282e08c6b5c8b04f02e269eaeeabb24b25eb31f5ea510f3f365b884dcfae99b5f529180ff0aa425d3b72bc985b8cee673955882127e7d75ee31ad9971cb87ad09d52dabbbad9a503cf17a26fd6ef6b4fbf4a88c3da769b307fbe104be7cca9d8f19dfa5dca0faa2655d13aa851758804c78aef591ca180ef434868b2d9f3863ad405ea7cf6de87253dbde2e137bac8f79f939277d78bff91fd58d23ced1f43e56f1f11e7b51921fcf3970b84c45b9f0a1b1bf629329ab49f818c9ae62f0cf08a0c8c6c9e82b764e857d33f3c4988752f16cfdc04d71010e1c0543d10af43046425d490890119a868277813be11cb5ad6dee704046b9cf8380abfad6e4365e4152116bd5bb4e63349013ba6f578f50749e99ba51ed8379673e74831dc5531c8815207a0ffc0cc88b533920c6cebc72486fc464a0c3cb0ad1fb93be600bc0a782e0cf0d4f7268941308961a092182cb33bb00df032005e01c03311c091d0ee09e352c0c6458d53b6cf8d392f1e6f2e311839253a000338e7464a0c46b7584e004b48c244c62003e015c48f4bfd1b75a754b477737abe3f61ca1dea094e382867166cb8da09aaa61b0b7183c937b658d2bacc35ba776f79e2532081581a5e660267436f159ede3a56ed12365fbcdfc9ba41fb25eb0c353e89d7c3b496aff61d7eade468c72e1dba2913fa8fe3006ea17820d52c871a08894b582e3ff09ef517b712a2ed791d6f18fe9a50eb23cf5b07d68ad031ee3502ad1e6e3ffe1a591f7fe759d38f900758c6885ec76d7f46f26375b3a66c512b43a4c0418ea95342d7a9da4730f0c007c98552a7e4b1ef99ea8c54644840fe28c4b5473f34abfb39429c75d1906bfeb64b8803d71c5cf3ea03ee6f42a5bdfe22d439d459c4cf5f2e8c2f8e37b499c4172c49279e3f848f8484ef336034e6fccf944e2e43be75e38617cbe0de1e4e38709eaa0e5135057c82c44d044433028806023bf7310181ae7b0404269e7499c069b89cc7f20d739f59293770fdfbf56d3e937587c99deec85a289fc90c2d6bd55d98233739a7ec570da889f44b0cb1b6912308f2cb2f8603b098543b7ba72af222c79f04781900af00e0f103533ff8b9aaa858b400780e608307910dcfe5417f55bf8222de6d5225c201c83825bfc460c3731900af00e0357ca0369631f038bca41883c89975b67b53e197cefb4fb9174fb985240eccc68b2a99eed0060212014283a2bedbd316a9addbbb2aac6ec3fafe8b492080178c27321886086f5fbc8ba742b5e16d305f3a4344fb229badafa224256b580f5b42eb4639c38598fdf5843ed3e15c40d51d1d4090bdb81a0ea6ea6aa85f12e2e26db7560de82ac4a11f743be65177dc72459ebbbf7d2a185c076bc4d5ae9b6f4a76da9bc7dd2a0feadd6dbb5c2d259c7ef5e7bd78d1d342f46edbffde1692f5397848c721650749823664e95bbb17c9b1ffb0ae06770411162410261bcbc350cff0ea36fd0fc948bb5e883ffdf95f136ee821c419a70c3ae4e9de421cd0e5a0198f7493bf3d2fe5a053e4816bd55b9fc5bcf24c8c1b8e37ce5fae3ae502254aae6237cd5f18e099f659811573079abaf5e5766fca7ed66dab995af312cc17645e20427fa5375f6e410984c781f80888b1a4063db067058d374847c8bc081349815a80701db84fd63d2ec4c29e855bd63e22ff4fab5e7de345429c78cbfffcfb3f374b54c369b7755a2b1fcab262a61ecb89c606381ab662d0adc2289025f4c6828d8346e46cd08c0e57ee9e388d51f0c64211118d8c56218a8cf07b7c8f0defcd061b03a4d5465d24fdbec842235736c0031315e15dc8e0d9d00f484a6e156abf2f62ed420b47355feb07e201fdf5c685f0c987fe67c17b553fc17887042a6e1cf03d2a30d1f18d8b03fd0803bce1000f091ec7bb90c11b1e302e850c9ede8f4281cbdd06787c9c71ded4383d21d4f1375c900a2474178c5039d4f0b9053733c256f574ecc089c7cc9c078a7b636f769465242ac4990a4fc40bc6d386f9403c102f87b57deb187e57c4da8bf93804f43b1bbdef00ab7cd5ded175cb3fe75f28c407539f3ea26084faae0e541cb5a8aa02425b0381974848dcefcfeb79c359a7dc26c46129475dfff86cd7901e1d1efa87d7ff288e9d791d68f88624577bd44f42b41407d9ae4dbee767a7e5bb75e6a053d7efde2d71eb5b7b6ca1fca0aeaca6f9e276f20c59587fc94e8997b5c8aaaa7d57d6432dabee3e09efa1e8837592e4a6ffa5c9991d24614ff973da693d6e90f5a6d49d3d24c108cd0a1dd0fd18e1badb96346b26dc837e934be2093fc457e86ddff8f2f9f3cf271272fd3cf0ef6713fc22369fb82f62edc89c9a6bddfe57aedcfde75a60d0a3e0e480eb36fa37d6fe2bb43f869a393d245ff691048245526955f008038ae25369a1ce136d2572884aeb7f78a75c1e31eb2a8abb7c2c3986c31fed71e3c152226932b6594a8fdf8b384e99eb10939318485564d6ad6700bc028097586228a648f4bd53153189218ef3b6015e1ef4370cf0748981ab8a8a81e3251b922107974962e0c6ba71ba7343032a98c4124309937cc6412eb1814c62301a17717e133b51c4d990745522cbc155ff565d9e2b81cc5cfdc15353c00d1575fb5c678c9c760dd84250e4c7c86997536b3eb9759dcba1766b75e2a7779f1c9b1fd54fcf76941bc38324109454b9c417b08eb96acfcb999603bfb31aeab7cf763643a4d5cbfe7c3cfa95822786c5bcabf2cae1a0a9bd978d470d1b0ff9f980b4210f1cbb5588ae6f1cffd4888972efe6583bd2ddf4f716c79faf5f2e39027e41e371b035d55569a74453eb7b9c2b44da9f9a5c79bae49c9bbcdaecd9014325a158d874f039f2fbf4922639bf97e743bad5ec23377b70cacd6977f5970764cae294ea580e2a61e576f89dac57593531afbbeca0fdd6487c730d1225d700706711d3fc99ce1fc0b7eaa7f287d7cbf539ab7462d927304f2441a3e481f386f3f8a2aa2977d910556304bacf886e2cfb8a80ac5515a9b26c6823e118ad7f4f4a9a7cfdfb90e4f1ab36956f7693b22d1935f3f5996f4bd1f395439b96c8e70eac3e78ecc99273b4aaad9bd36f10f1c6db8c58cd554559b0a047e241a35445356d2b4ffee91d49b0eef961b8237fb9fa9905674e96846ae9a1b3cf99f88c105f1ff261fa98a385587ef5dcb61f4a4e6c7d9f65d33e7b45e2e594b7582c0f12eb71eb8f3b66bab103cd0f73addfd62da1264d8f168d5715f5635e6726a35ab2aaa27e70702569434ad6eb2c89247036c053fd26db4623bdcef801d2581b9281318814d6f58f1190fc0f9e9e324541226f95aba08ebb80ca2d3590dd170908dd0f2209488b6b5b2d88119009273eea1210d9ffb580871a8f121adfdcd8e7dca9c15b27b96c3c54bfbc75acdac1c93213f65b62a39e07d56ded9b95176dfe5a8ec32def5d3fb9addebf6a50752001a9fe03b45f16e2b49b2edddcbd9b10c71c715ac10b27b97687d0e466634522860bda7870e2fae5b601a3513fe178908a9933145c65c4192b4184541b0f09cf82b60e2f797c8be039d5c6649444b8a11dc40099e6af08090bacf702d82780eff6d19bbe58f06f21be7974da9a3990fc13558eb47e519204d51519d1210094bc1021a928b9f3ae1501c50a7a60ef0a2720ae4ef2d049dd9e7275c63f5db8f20efc1ed36ea742923bf4c76f0a2a84a6bf57350678b911c35d671ebff348d9f17e951754e43bf2bbb79a171cebe6e2416fa87ca6032e56edead6950f9648d2f16dc7699151db25617a7556edea6bd59338704889c9eb060f0cf073a7f4de70c5aa582c712c6a999b76b810fd870fbe2cdb8e39059c71c92512d7754d4b0e7727cabcb01596c51243b778d97dd5f79c2385b134e68612646445783d019e03dfea07bf6de294e8a056ef1d076f1eccbcce689c698326c6db070fae041e6c2d318c0b872734bcb98e7f1ce4fef2e08944e3529b555dbe658b104f9c73cd7537dca0bea850245b94dfa9d73b77aada559db80575fe683371ef0769f7c591954d9a0871eeeaebe76dbbc51d4fc4970869be1a2772ab1e0c6d07f054e36d1be6c764cbc8268239527b9f693db0f9af1f5a5f512d39f182b4bfbf7b8364782227d42eae8683a51c547ad5703570e5c7429cb0f89c8f0f9784e5a453cfbbe5c543e45ebe32a557ab0566f871f8e743db56fd84b6373ed9da78240f8faf2b9b8d8f93e478e07a56f0f269dd2687af7ffef2017ed03e407c75f81c5ff44e34ec8b65cbe7defc9a3c07c76e7e62cb44309ed37a0695eceebe7a7b273c873772220345f7e08057229edb2491f8cabe0a243415478e53f59005af5d23c49513f2ffe348c4ce7deffa9bdca4636e419b08a681c68ee1c6ad3c19ea7e42ac3a6dfe81ab25c57cf7ac870ef9e30f427cfec6e897cf6f2107e5a25d59731e1714a9593ba0eae61fa588376dcaab6fe47e28c4dbd38657dd3243118e458a57f50df46e10e5778197ce4ed0fd9695410d46d532d025ee3847be376b774169a9109f38af5df05e6f215efbf4eed6d7ac16e2a32f5e5efa876512e7c9bbc4f76e364e87451a0fa7486f88a43646d44380178b78775804ab17990d014b0111f53c72d910f14e11f78608e74644bc033c91a3c17344e27ef823bcb57ec4e1a7f7c3d123ea699ccf326f07536930c0ea52a84d11de384e98dbcdf6451c67b1dfb179308cc720ca80108def676044337c1eba2a34a78964d0aedcf9e07b0fc9a32863fdb119ed8ba1bf92816af141eb9753ff21c415afdf7ffc1db74bc23162e08bef6e9407d721d63897703436a23ec1ddfce184e3c13354f0f1308f0fc2cf6ad4789823f693c397cf5fe0bef2e1dbe0fc61060513fedfcf99de767eabd8933e8697ae62fe82d5c800e34e08439bd94278db5ff6b50d04240c324a4ae1ab775df83237adb1b52254f1fb3942342f6eb5e41ad9d1eeaf9c74847bd02f7965e69aa510928f5e1314405402801d55e100442501da192ddd5e2e37c0e267bf3ce5d34f2567b8f188b93f49ce70e6f071bd5e949cd5c6c7563fbf0d44710c84aafb93aab97b62f52950a397097a9f804848ba6008acaa7d06da40506ad17be57e49649ede3c7ed77342140f9879c8a7a70971d4fc7ef77791fd485fdde4c14e19223ea02e7176559f3714798f65c0a814c4fe722f1b54998c06afaec6deffc16d0f39ca46634d35a8b84a1a0e7cf4b929e6800e7f2aa89cb88a2bc08dd9a74acb010e8fe0311517a892226fd43d5d2e198559df4da89ad24e3dc9afb2a5f8865ba18d596613a9b09ab6badf5561753de784ee3115164a66e4dd47b622e51cd1ce375f05d04f9df3cc609c32f7ba9b0af04c2a2eb32d4a839f7a69fa55ade4baedf2d5710f9df3b614588f3ee37727ee12a24ffd590f5fdf4d4ad607b43cb6f7fb225ea7aff035ab3c1d6861bb00dab91afe45c6f5dbf07894c029e0ad2b1bc627a3a1f1f0e1ebc1c7534587b7a7f88e067826155792f87a92148e23ec0b5071452aeb6eda7da21013fb3cfff8dbaed7dbf3d1f76bd1eb0acf27e63587b6adea43551d81f88f48dc7a8ed59cc57284a1ec2b09c4863aacb75d82122d89c63616716896283fe069219a8d689935ea65212edff6c0752f7610e2d017ba0d6a0692890570b063f578510d1ed4a05270377ef48afa47aaa4c8fde9f3af4d9eb043882dd53f0cdaa2941ba26234d428e24d85badc507f08f549ac0df5eed7f59abeff9b1f5eed84ead777c909ffe0f6a77b3ff0a094489e297fed9b961e2722fcd9559d589b272fb4d5f30992eec5da71f06c8017067885002f0cf0d4ef1d8207fc46d48e7f2fa53a19674cfa662b780cefa0acc6e328058c03ef054e0e9ef75f99abe18dfda07118c752ca18c6257247dd0d55a09a3116c0c8554d265172155ea6943ad0366547c6f9f22545649223bf67e6988653c644fda931d838eaf88a2a7152ca979260fcd4a2b97bf3a0d526747af327e3e08775f8c29ce43321fe22e8c6cb64c70339faa0ecd6415761f36cd9fe248689f135ed37c7908cd4846fc0cda5512f755196363e006fc7d39b6efbee12d93ebafeaa7ac6d804d5285113033e5c6f071bcfb1ec2b09c456154a2014e1290956af57b35a5f32517e3729f47aef03848f330a7d9472bc1b917e44e7ccf1bde5371b6a965f39ed13b9be57edfe368a0405e0214f8057a9d45f0b35da2ac0bb00757a753da086c8d75a3016d600e789c6c26ac8c24a9208506cf2af46ef068c13000eb60e03ae90b2c34d6c75433c7c6a2755ad7139dd8d7d563d34fd612979f5ef37e4fcb9b24fbfb31e6bde3381c4c0bca11a8878571c2f1ae76c901838c7c5bca17c5e25dcf6e0c1ab80e7f43810b3f112df9301f0543f1a29319838679ff13d07e240a612e7efc05fe41463cf573f5ef9c5c6638498b3794acde72c25874f125d0f6d304252e015d4ae91514a20bd5c09a4cbd9277ca8241070b3e511e4a375af38cb176f14e02cc125b279e86d66bda0c6c710001a646ca6f9c73649b8ba445910606c3644bcc771f4008f38fac4f8068d47d03af02460abc1f14089b724d0f6a2e34bfb03e0737cfd124e627c4bd87898e62f3bb144b9e2866fb74f3a4888e5efcffb76354f2dc334296444875433a84921891a090ab03cfce64d73d9470484dc77c3d0c6009f755244be3c6bfd25cfc8cf2eb32e74233b4d399042a194f69daf13a2eb9613be3efb47c919fdabc5b5df5e2009caf815d377802d02fdf2a31950a384c2ae26c52b35d1eba0162e5ca96103ee0bbc398c7d8f6e8d2c42b9ee5968636e197c1fdead0d1213710a474aa9e4d31d6fb984e9d0a15d8fdafa2f210e7ce4e0d7cfba5ec4e78672605c0c0b8f368a5a685c555442eebb78f087019e5ae849aa8a28702a9fbc78e669f032d8c19fac1bb35f05930df01c80871bc606786a5ce80064de6c53c9edd10678093764e5985dc3d7ff20c4dce73e7abe285f0d08b9abc2bc9317cb36f8bcb5aa2371f387a5c531adb6b84e215d17f5d97df7e5c21dcf5cadfffc42a952f0c2ca40c2ccbccb3c6f9b0cd54f168887f032d90555662706058f474cfb097506e001f3448c40513cbe0d44bc27864f81a348a882025603c6837b4599dcd983c6a38445782321c88036a98c1a89af0dbf1f9de4ba2d32306ed98c5065d339b92efa85101fad1cf5e62b5709b17beef67fed06679e1af41e44c2810c32a8b28890c07986aa2bbae80b0849f2570aef2b0262e9757ca468afda33465c2c452f6b86f5975eeed2f74da0eef5639d16fae3c172800e7ea7e3c84193a56432f6987776ed9214f898b97f2b768d7e9f895118f18efef9382014a888feceb7431b6feac203033950a0d048209080d0cd5e90248e72c8408ea40824e5237f6a885846c907ef808eb01bbf5c896a45c6dca295f2b93e9d063c30d09163f46eca336d8e12892486d871c775a10d2c6c95d2c39c1b4a3def71a0ea3d9c132b21c9a788c1b3019e76f007725e96211300da623c5dbb0df054bf4d9cb945fdc0f88af60d8dcb8e6ea55d162e1462c1a8cfc5dc52d5614afe87840475c567c1e760e3c21bf68880480c5b0c3cf0ab5429a97439fcf8f6b15426b61c319180131d0d190bda91575c41accd75e1e61b367578f3005e18bcf6826c443c62da1ff18eed5c68dbd04b1d9e39e2bd40c3d78bafc855fd4c52420d1a0fef8e70be0e6c809f9b683c8c11e445942f438797ac44cdf11d4d84a933400def09be3edb11c47155dc5dd66ce569427c3ee5ad411f82b71cad5b94a08111260d0aba65e3f9067504d631119046abb0f6b51756186a5b55ee104697467fe72e85e8708c1c661703a1ce2f076f9803c1ea44f117d76ba4cdaa430e7a401ec4397ffa7bfb918b85386475d75e6d2e86ee3ca4bf1e25109400e860b848d55520caa14e1cdb6834a71c3f6884fa94d56844afd56b5489d5a228f9771d8e6694bf4df472fdb2ab6fab983c6b56bc4e95bc316c6d5cc2ccc660ba000bd3cc07a46bf7ebb27db61284a7dd2f62d43507a453275d3ed90a0c69c54d1760719df070ea87cdc6c5d1e1a9e777b62f7d68438ff89ec6e980d1eb0445f941f13d10dec6c2dafdee2a826543bfb2b4fe23fe7863a27f7c13dba28cb60c80770cc04bd646e4e8f03cdb00c337783d986c6709e1474d17956519f0f5db067478a6eb068cb61e80671bc6c3c33ffab3e0ebed8f84fb2d597ce3c6db01fc63f0d6a62d7eb6507d425e56116048f19ce3353d870c2cb381708211ec7d85653fb9f152564c2726265d1de3016c66546513c8af8ae546d5f4639be566c95fa414a6a6377b4241483b5bd598fb069540a4ca8283a3f628a841e423d10e233991400021c06c95946c0f251a3e610fe8cfa34aab96a5bb265d24720892a0943f525638fb766d5c007bfdc0a4833f7861dbb1cfd13dd1605c361efc85fce0f719f1193cc3c1cf1803e1dd07720c3c67c37bf1a077e2e105deb36293317310eb874650715cb6166f68bee16dc03c6aa8c350c3914fe6704e7050e48fc7d74fb0551b8dfccc88ed1df4cc481e4448f98d9d821b69099e0e9f5f49ccf1e54661ef601bde20bed1c4f07df3c40fceb03e1e41f7d724bd7e931d0f8f9014360e5fbe1f38fe81fbad30197ca3c01846064406574909d7f96cccbbb3e09c8b80ad1755ab980414cf1f1f21c15c576cfd1221b1a1764492655fabb080705072b33f0a9179e9e9cb2e961243e8f194a1bd5a8a7811db89fd0645ec7e24f229674b6654adfbbcbafd5229397cf5ce84f1e3c72bf898251507060f74cc361981ab4beb20608602c230491e1a495105863ac223f59a6c2dc8a1420428ea0e6942a04d4be95a68db50e7aaca750a68ff7da7c56e60e2c11b3a76cfeb171b1701e352a08d8b29402a83b9fb9580111d5551c62494f07ca01137c9fb243c5d33aacc04c02b80be2b3cf349459003fd28827e08c0bb2021defeb4f5086f18c0cb4b3c2e566ccb3aa78e99f366aa10bbc66c5dbb1b22d16b408a20d11f25d1f7554dc914d1af1e55586b85687e6dab9b5d1b48977f1d7f674c856572cfcc82c0bf5250010645201790f13917e0d9aa5f002f53a9eaac7949ba419bdd4975f85c05e3d9063a37882fcb2e8b2a4a2f4b32da06d87a2b602a234fa55a04fdd2f1f5dc5cf3607c747864d44f723c7c467db2e1a8b6d10941cf864bf8fa03406d03be5632f8e2fedd7cfaba99d31f1262ceb153de980daa739f711c6bd4702c85ef8151e6ce3ea44a87739308c75a9164d9d76ebc50280ec4fdbc507ceebae5468d2276142510bc7a3621e5aeb4cb5f5b0321f878a73546b0f3ec9ba4da824339ba48d5a4e2eaafd7148063727f43112f47ef2fff1e27884447245c4ca27125a19297163df5c381c03917261a97645545b00cc62679039dff0e7907dea3493e283144fd2a3487c1d32506136767921844e3541a096e244cc8d955debb7b841b67f4e345cb9d1d10df518f841d6be4d0701e619d906492150f512fc6f51c656ec6d186dd338d9c2ee7948b991bb449b517ec4ecae13bd0ce6a14be519f0a15f177a09d95103e735715413781728924f9f59b783c7c123093d01a8b2f977092c557f8f085f18fc676d2b70f7d72e23450a993648192076388a9e64e3c78ae0d8f7f63dcfa86759f7cd9df91e8f92eb58b2e720fd4a829421323b133e9ea59f5398b742defbde3e09f40254577599f0b35de690da9515250d21aa7d7bed425583342c007d8a8fae03527282c429426da2520172ebaa5ec5cf7dd910bd60f4d342ebe71c8d2c74fbfe3dd1799edbf633c8bc1d3e7c31f819bc9e099f00b27c4cf1cf91b4e8c9fef3955fb2295c1629163e807e0b1be68f9c58ea3c69b083a4a9c98c281ab24f1c229e4d490c084a196906b2ea84c71bf378e0bb6bd3be5c31afee6fe373c3fc1f39595103e9f87ac86e1fbf0cd6a1cbe41f823bca4c7c3bc1ff66c3c4cf0ccf39914be4111e441e381eb7ee1cdd327bfb44c88efbf2e9ab61abc4b6b98ea9d246696fb0a55f474f32012129e34d16675d2657f131059a2cbea2f8805dc393aa729b871ce33b2ab360f3c3a2c7a76ea230a26e5d24a5575ca0055d3d59478c10c3a3c16072019065ce1e06ffcc0eabf23420470894021018b272c9dc45a37d797715cfc014dc3d53b98aefc18c691fb395a5bc1d34dc451936efc18e6f41066b60d8749263e9d2eebc73144c6b3583fc21ade6663a8de8f418600c22c455abfeb515831076c6534de983a871b19f17b4e4060c3c5df35bdb3bc343346801e12ff709d217cf36653ff6d684735fcb9edcfacd3d7e77131049e9a6c45c1c6db84fb2fca25493b495b94095ff3fad2e16519f0e53699e16cbdf9ef086fd478c449128e86af49b2e6e3e19f3f24a476427c93b5f501be9fbcfaba331dce319238507381b656544d611b6cb8c408e17d1f1ac6c22f493ba291655f1110c7fc55b42a5ab77b72fc428bb283868c51902b891d3ca0e24ae99352d9748e8210429515a685c78baa30fe040909deb4610332e1807ed801df275b108e03356c299cc8fa7842522a3a366d1a6b6a1bdceffdc48cac5c45402a0ef5bc77501b1676d4b751f48dcd5526fe833f0af08603bc30c04b7cf01753ee2ffd20e2c64b5f843033dee2861c87c65c1ddeee8edb9f5b364a885537ce9fb969930248aa4bdc58cc8b8502510d91bbb46e602462df1d503f77f71d22fe0009c3b8e8eb39300239ca0f7a369e001f72a7892423a68d077d6162959979dd717cd97c717c03545c81aa5aee1516a4e26a64047934ec234c3afcc68f8703edac84f89abc2619bebb7b6c3f78d915724d7e5977335d7486b60c76f119d52871a06603afaa652a793a7f6ca8392149baa4ece90f1b2e74e564b65ebbc6f4a33a9dbcb4c7e3525a589d3ac4cddf2f20ecd0e2c62ecfaf9f5d15ab9e8ffc3552b863be102b3ef87ae32c50651185c6fb1d1885ae05ef1b8cdbc0ab4cc938be063ae0ec61c74d65adaad0b980dc9a95592d2621f5fdf8bc875b7f22c4213bba0cb957e55eca73cd701633629b8c96be34e03960b4f522bd99511c9e4f36e23d13ee519907f79e987270251bf19e09c6c5798d355e1afcf3b32097582904d6c1b8ac1efc7dcf897f95ebe41ff32a56a0771daa00c0784e990720130119d3c11859f78eaa493201824359a6d7c9ee743d7df2607784fa586d3adcd3c07af6ae3e56fd2d51712371f3383a61ff0d7152749f0a18ad13dcb0a9569dd159c2179867011e0a7e70c4b4d520be682c6611e409e280549ba52bf7dd6343c66780b79711e45e3b30275972e361c16e0fbe262121bed18b230b2bef12e2c3ba178f72efa4dfb162d3bced10c85a839932c0385e7505b4d1688e1933307e0d8ce518404d57d776024c6ca197b5a291655f111038288970a064200fcace438eefd1fa2221d2bb37abf9c3dffd1b830e9a7c4ae9a17be9c042083d9532c935962fa99d593ab59ffa0239482420387058534a0a14ed56a99a544c9ab02d3c4e736dd25d6fb8005c22b050bb12d2299f5fdcefd85b846832b4c5c0bcf31b1897d1466f1d5c88b1b748c2910bed79f1ef4a7a6197b088e47970e1559037d4681a35fd60f2a7e2600431e00e79cf6b09068f6df879ba5757a46fe45c57d29d78e9b377bc243754f5c6ca6995b0e16a1981c08d878484bc5bb6c3f390f61ddd26f9fd36eefaeeb1fed4bb4f97eb29342c745a4f77a4bcf4df19b167319dbbb79e470334d5ffe4d37fc7e049c2d11eda70877ec30c460311deb9eabd041fdadccba8e1886923be2574db4f1ec00f27c437e8022c824f8c8f82976c04b9613ce292992a784111e441e3c103404b1a87efa2d367747b79b910df144cfbf762c8d987779863ba7dbccf03e3d7f08228b4819084020c129e733c43c75eabe8f71b0141159294400ed8d836afa25c8883761d7aea5fb6c69eb2dd5427164fade045c4ea17f0c084847aa40c3cf04229ea5db5fda019338428fb7cf3524caf5e8ba94430e508729c18d701a947ea4e5035456222655e0b75186aa771fd37155f8a171c9f3784387ee23983cf1a2025b3c969a75fd025f62d1e98ea692e3114b11b03b9bb6e0e480c53496270e02f2e6c07e0a9dff31b036961c3c6c88103612acb32cb73701922dee3e0a9f7e480c43015e6976fc41276d079d94a75bc9153a4d41e8af15877d992c5932e1562c16d9fbfffdd0ef502cab67ba55e1321c100529448c02db20e52dfa06a8b245528ee9dfe479dd9efd9ae727da76c4ebb23fbcc04e3eccf8eacdae608f20ce87faccdddb825398afd5e0c84f1f3180c5b835f409cb30ecf8bf0566d2f82bc04da61c05f27fcc9e2eb3120d9807f18e01725856fb62f823c4383e7112a7d7d992454c12ea82aa10baa609e70bd353227191f0f8b13429e832b31bea5e11f87bae7d8077ff9f7f4f160abc5f55ad941d5d570052d12106ab3c067241c18af863901298d3b128e0ca81db187653f1bd15d0e7ffec269f76fdd26a9e2c591655f7f1dfb340c7fb9eed38e7d1ea05befbaf1844bfa834a81c79d58d3f5766809d4ef410dcf939b31d44438c27bd2cb0485c121028bef7384481b94bee1cc0e0d1ae7c2f0acae733605788d6336246f9c193cb49d446df81c6d1b4e627849bb2726345a12dee358f661a1eb861b1df15e0c92c7a8baa9ee7d318591b71f9806e9f82909226c28f44ae13a65d41d932d84b97b93111d4614379e4b58ca3a6ceef4f129c26ccb209b1ec39fad676f1e13dbfe087e0ef08d30bec66cb3cc481e940d37c17c35b8ff8cf84669feb212c14f1a5fbfad445f5ffe7da2e36bda27c375a7019fd38879fd363c1ed1002339b31d96656d39f3fb4b84f86f97c7ae1f05aa27be3ec9dbea13bdcd039fc9db0a6d1fe814a28d54dcfab5c55e967d2d81600d3c6bbc2aabdb8d271edfb6af44e180f4c2ec6ce10f6cc36cb2fce62fa64b6dfa5ccb6333e494fcd06a49e9d46239a89f55ae40dd208a6e38b0357de073e6474d5e3638b0195017409d0bb593f410e805e090ca231f6a49d8ba0ce993e7ba21670ce9ddf7b977e533b345bb666e3a787f6e28f576ce819902bc7c3a66e08882ef90470e0990060e330738b8a94c22f4020805c02b0078c8e13a002f1be03900af1fc083d131a9d0b8caccc0d965aaf69a59dfcd1f3b4788ef1efce22d37e7955b304710e604229515ba3fb2eccb6803411d72046e2624093517fbaaaa90942c4b9e5ff8f87629011f7ddc690b2f973db3beb1cadbdc1e879f0db63e5f7664d8c619600bf15424163ca7da0520bfc2bc490944a9140772152271dc20491247afaf03bc2a958fa7ff8e70862f9754c9f696789de52699838b2495007cfd39b8747c4d7790737c4ba85d00ed8c84f0837292f1f1b04833a0e019727055cc2d5bbe42128c31998fce78f2cfb10be9dead5059dcbc24ae205954808abe1ace354ab904eb95182134a2a35b3ad451d4b020abb6166a47ec65d9c7048422ad5132c0a48af2e06cdbace3dcedad843860c94157fcc90d04f4eb3eed584dc9e9885eaa361c98d677a122f74ef4832e3c2cd78df45ef3c682d71740a01837aa9331e946a89c40844e00001c4c494441548f563511103ec0af431d2729c44a41d008e8cf63fa79b27960fd8610e7e5dd34e5afcfc8a9989f3a6ba01bc9cc23598dc66538e84daa01cf58cb23bdd5f7a6acaa5e1658077eaf36ca545fe4b80df032009e03f0f483df3b386cf87d1ec0d3dbc9a6e93644bcd75d573d73abdc80635e7bf4a0e72546f56323c5b4119173830d59c5084715e89089a383e474987433f2aeaa697d20a3a18e742d5968f793fa0d3d52129a50e79473faf513222ec2fb3ce8474b357e487e0c4e249e0a86cf9b1a9781e24ef89d9a67ae82290960300cb6810446774bc737c96cb8088fd2aa9b549e0c7e10befc8ef012dd0943f0bbf80322c805e2c79d46b88a36d9f1c880effd8c500c5ec5e96597af3c5c88f71f7dbaf8898142ec7ca1f48b5d23142052ad628e3e24202a6da6a8445b0710125ad7a8ba02491a8de5513cd710d302a81df133957da4c2f2b98539f0392a3fa46835fbe5f7aadc2b69eb2745be5fe2c66570916f38a6232711d08e871265ee726daf3cac26679110bd1fcfbebef72dea498c4477534dc4ea54a8e1e0c038120c34a4c875507d910405dd2042801fd8896bfa1d7b3e0484c855ad5dbae9ce4fdd9bdf52e7a7df606789b8c86cd93311a7da493e3256570d7891de8e0e8fa98a7c11ea0655d170701b0dcac1956c72442f729cc163eec64946bcffd86e45e9e7cfc943ffb29a7198b4323ed23f56b37b3f303b29cf0c40eebd90a286447f4d7927fc81a312a3dd39db8f8e397570f7cce110f7e2b079f4bb4367b17189c6f797543c6341c56b52c1f0e4a449469037a092dc337c93cdc165c697c38736c00b7267770c714b368f0351e3da08156dc2f1f0abcad4f75b0b7e3c7ae65942bcf5a2ddfb61596f5bfad3573bc0664b2a299028785257aaabf5e729fe23ee8efed83b794034f608199f9fadec2309048bcf688c072a06f649dadef44f2dfff985e4d8da2c3fe4d63c5b7e38445c997a968873df0511d0a6fb007201a6a380c0e79d24cdef2244bb778f18786e0f210e3feae84d4d25e7b86ae3b7abbebd50bd0f250fb1595538e05658c79328354a1e79f09cc5fa63196ae061425d549df206d4b25f7f98611f7987241ccd1e6bf9d23b6fc7f0bfc6bd09ce1a692982d98e386d8585973e3bd6ef38ce477d6e037d2ba1cf15073412daed54d8a4275930d54891d07b65c3b89690224f00bcf3005e4b801706780efc3a03e0091d3fa62210d00f0f3fa1e3c7eea7b0e17e8d0ce20033a09731bc4b5bacbf64865c4fe3a63e71fd9beb152c727384ab91dd24746ea9ac84fa23a8f17bf072418e8e6c2290d9a01eee5b201516f6240c354820d65a2901bfb7e02337434297bb8f1fed322e299bd2569d7a6aacbf5ba0bf27417fd702ac0ce8979a37baaa18dafe7156e3d142cc85b68297cbe0d9d02e61f06d9d538ee3c4117e18debe36beb77b8a6f9c4a2a0cbfcb80df69f01bc037231e5f092f17da1abc24f05d0bcf69f88acea442cdd84bf8561c54b1eb93ad35df3d23c4c42b9ffb6fbe3c0767df38615aa11c89bac2da372a4f56cfa031bcf272a8c1468b2a2bba39b55c7f9eaed406c983ae1960f11e941b1025e7b0f899cbbe22206b55c50f54aae1407603fd36ce5bf5df8a17e4869b7fc2ea56f32547fe4adaf893dc3cf799a02ac19bd73c115e9125aecaf1bc7e6cb76afa5c8bd37af796cd6f7b8fe8305872a8ad97dd33e75a79386cae7eb60e0e882824d32333b30df88d66fdb0597f4aa0ee9cb89f2120182e0169b1bb75852be90c3af39ec71e7958f6efb5d4290fb8aa3557b4ce8bc33b0b44e1525da71ae83668f2563224eff379bf08dffd0628723b002f1be029afae71e0d5956df09b174c0565ba002b0bf01d872a02a6d20a5069543d5df1c98f438578efdc27434f1f283793a89a500984826c19c8d1018120f747cc828c6ebb702f0ca9acd05f1e37e44dd0339bd5c81001d10ca1a429d77575a4fc964552223eb453f727af7209d349e2fa1603ddfe820d299bcd9bffceed0c18970218171c67d5f6bcceb40baa8c49128bc88b4d87ef8f7f2881b682674892484917b97b31c3d7536922c3e24b9298781d9bf035dc116ec2374e15aa8f8747a8d4fa32a8b812b8cd17c17309c763d103d35b3db750128ebf8fb8ebdd1be4e1ffef1dcb773daf3acc250db2c5c14da74450eed63f47c607555c787f0dd970212720b9e9a2a4910bf55a56ff6c655f4b203a6feb3b8051a5e346924746d7dcba4812920e83babe78b514c9acefad1db1886cd3c499379e5ab0a0534fbfa859e55172223b457a2de9fa8dfc608bf871999c98adbbd76f2d03ca4d8403f1c40e00a123c20747381188e9ac4649a3ab10170eb975ed09238438ee8133ad31f2fda1d294f3738a85d9f6309a38fc5ed08f30f4836f1085add948e7403b57c1838ba54c07465080176ef42230daf6f319156d784a1dfc4cf7eedb881ebcc457bc06300675ebaa1fdfb64d888faa47e53f9a2e259089eb5fd90ef7bbd4cc5775d58150a32482840475c84860f09e179438d046862a0030c247bf861a3839ea890d6dc650b846f5b2755b46b917f6742aea1d71df9b3eaae91167a7094f7a4932dbb037cef0b6305d58a534e33970419527b1e23c16a8e78c362907e021e140f8b6d6363318050de34bed5c6823fc0c866f4663f025781ec391db20bed90c5f6e7c2f315c5065769bd7e0572d2e9fb74eaefcef7a177ef0a29ce79967bd37eaabff516fc0839e6e38854040b46de07ae4711d14df012a2b6474284d3bbbb08e240e18005dd92f7efec0682afb9880709b001192d150838ac7dd78dbab373eeb0ef89107677eb6fb39b9e1ea9b7d73b69bf77e2d898ab15fc771140d6e3c1ed8967a54faca0cf99e0ed33a77bae023f99e493dffe3265dacaeaed8b25a1e183b976c5982ba47c28fa74219cdda923368726bf359a9c70a3170c4b067c352d239befaec7f3c2027b669a4e588a7fe251fbada6ad9f1558d3382b1600b3a0b16b05f62009c92f456f2e00d03787989c7854b0cb8710c0158283194ea91b7be48617ffc0a124001f0543f82af7885a29eafdf56d7ad5c4a8c859fbefdcc637f1262f5b8ef66fd78bd7a0275c1d540389063ab423f79241ce82f8f5e56e8fe88de2bb821d1f88812ea5ca81dbd26f76f201cb46e60bdbb12e8c6b12b2f5c7a8f94b05f3ea1c9204990ac2facb456178b78d5870db0800c41db81b6c7308d86e7543b0bbc14e7f99c0f54db8bc3d0e1d33e22950bc0c7f887c632180d1b9b050ff84c94665fc39718435cb70c3e6314397cbf338603fdd4e163c4bbe72596110fdfe42556dea6ecc3e27652d2387c7ac757e53a99d2fe8587dceb017ebc6bd93f7f04152a19b7c1890319962a8c244723394a1ca05245c281120a8783aaaa08dc881a05c9c3678b43e71f5bece362edeb17c06be03d3c4e03931ea681313b1db2e8ba92c785b7dc367f4c441efcebd3c79c716302a0e835918f1c056e3cb0b4302f1df937f6bdc854df5b4ba03ddd4a738d5091acda794bffe306dfd43ef68d94546a5b57d72e7545c86662612cf9e3fbd1735ddd64ea75e9d9ad1748c2715fb3b4e3a4089a529ef6f7134e907d3a36f4524f0bdea4b0092bfc8833d217348f1c1fa9ae26153d415564764b74183c1b5af9f09c7aef48c0a3a7cfcdd186e7f2015b354e4101592381e3ed0957a8261f399db81f23ad6206cf4e342e91136bcfd875bbe4ecc6bd3ffe09294b2dba67fa8c15e025558b374c822451b156d5e570e0574c55352728da8d9022ce888e81573ced35b27636d4d84324206ae42969273a6de0f5022ea332a0e2baa7064bd6a0d5d5ed36bf005e355a31a878e2ae12566d1ce791c0680cb362b7e1906dc3e78d67501999e68d477c0b7695b23f50af61f8843f5b7741f8227c5b87e7c13748508dc5d7a25974e06f0c5eeddc9aa1dbde938ced811b577dfd8410cba7cd9d3b5dceefe2dfcf18ba0a24803a8c2fc2b000583f64ec46a70dbc89146d17d3f43649c4681c47af2a804757d0a2b11c53eaa0713cce89c3ebd9fe28fb8980708e8d3878880b41ef28370bad5b9acc16e2a4d0f965279e28c4116d7a9e3b65977039aeacd08c04b0935dc818998d777af7b496a8e78c0bcd0678c87939f07bd5ce5407a0dcbe08af51073f7172f970f0636ea825a45977183c1be025de807c1cd086b4c41adfe0b8e081e1c1b313e29d0907fd126b493cbcb87ee804d10e509564423f96f8c625d6ae3bba7a52694f213e7fe2cd371fffa79438ae5f70c5fa6eea41221c58a3bba38af116e519d0863ba3c9f8788ffe3b525d419c10110ee6b54204841592aca107c418a1f7df59aa4e4f97df6d4fbdacc59d52527df0cf47bcbe5b12971f9b34397b5642b0e1186c0341250913d7df12603c928fc8ce0f800f8c888f21083ae8f708de1ee08bed86096192f856f7ad18b16eb41065af95e62d1c24c4da9edf977cf59510dfffcda95bbe5ccefdb0fa1f78ba7fbad707af65c0005538e0719dd1454e6cbda2ea94240cf41ac414242ce0b50e08d1af877060d95f04c486d7e5eb3512129f24d244d5cde4c171f6eb43bfbaf926210e98dcf6837b6b1b78879f6381cf6921ab8d96091c1bdb781e8e3e0edf8196612383e4b3c4d20e7e12817df0020e7edf01dcf00649000fbe050e3f0c07bf6ddc70221eef2424869e498d8b0f1e7bef4838107ad281107bbe7c6259ee7229ea7fb2e3b5839f1d21c4c693579f5a5aaa20d2d5c0b82181d3ab0209a37c34d4cde1f37bf4e790f3abe191bbe8b6cb7204910ed916890b7cce2511cc029d02eb192591a6d708d17e52e72eedfa0b714ad5a54fbd7fac7c664cea573dc618e0c7dec118172eb10e03c685136ce3fa0b98b7b0228b494b9241490d6d80e749503640cd07787663f0956d0bda084fdb17d173c4e31139af911935f76dbb45ae99ba9adc2d72c757e6eccafba1ab9428c4c6c3dc388c1f1e5d72ff324920567fb160e5065085f20be47c17ce2121e1f7f9b01a1916f2ea83f54636b74ff59a22cf791a76765f8def7e22241c36d48ed8cf657f11102c0ebc16365c0809c9c3aa46498436dc89aa6ede498801cfe755e69508d1ca6e97769f7b80f4b7ee4bf9d2fc2adf42ce018e2d7fcf2406d9b2e1398535a492900b3e1fe0393a3c347a82ca2ce8e0cf018961fcbe95188c9ce71e4a0cc62ca8744018086026a962b2dd0db161c1aac953ee1062eafd2f968cdd2237d55335a328391c120e4ce980c645201095a09aaa28811a545864f3c0da94b204bd590ae3474a78571507dc1f432a5a6c2363849208aceb26c818fd8f109dafeb73cae12b84e8bd38fb8a172f97cf1c9ebee1845d0dbcc42f61dab136635ccceb5967e37ceb399091311026801f7db07eb49b4266e7275b2f9e7f913ca85ffbe9ab457245576edcf5c3767990d71d53f38d6b634c7ba7c989ee78a4ce6b729b2b99a57d956e357954b64f4b3fc35561a7be9a36d3d540847e48f92e458e636453dd37eebc45fe5377b73bff7503aa8b5d9564ddbdb5396ebb6af0ee27dda499a57f5edf7fcb9f25c3f1fdea66db24618e4cab1b42778023c78e71122ca54784a5efaf67f7c3d0818e8403250396361d3f4755a9ef9e8ed3d8f3a7eb35bfbb9cd6a549e2b0a176c42f54f63701b1e1b5b8e48157456fac14d86828fa37295375b335aa766d23279f77f16dfde5001f36bffb09fffe56c23825b42866943415cfab44bd3570e3b1837fffa98a748981ebc23de3a281c3f71dfc98fd75b07a6fa0c460033cc3c1cf556806db4b902a11fa119952fbfd8e51422cc8f96ce9c85e427c73c9b4260b2f553fc4540cb54cc4279515c66fa0311209489eaa2b5bc2ef180748120712103c60d0680e88373a4b293c479208ae6bb489c4a9b2dc8237663695758b49ad171df0b41059b75df5dcc30fc9cf8e6bd9fad2850dbc0bc7196d5cc3603ddb64fb53d824cbb8980807ad8bc4b6c5e898e83dee3cfc74cbcaac09b709317bf3fbf77e2c39ef9a77ab5a2381a7ecd8a822c403d1a48a0992f84c05558dd0539a3f06bf9ea9244d0403e3c37c3754627f0c81a73c7715111aac9150601bc7e30b563fa8f7e397575599cafe2620581c783d974450878c9208184b9b422ea2780eeea892df3dd6ed2d218ee973ea8dcfb595bfc94e7bbc6bd706de693389616f5545392213e029c2316c2f554539f0fbf12431c0d3c9a98a3cce9071f8811243e283df67bc25788d3c90b00001ab4cdb55b2f26521a6f71b33f8b94142ac5b5b7cdf46b8cf05ef6f41af28ae2bae42c90309c7eff436facfe3e7fc821d9fc4f173e992e179eab1a32a7e23661a787fa5dfa66a97d38ed510b0e8aeeb339ddc19d77516a2f5651deebcc3f502cb12592989bc253361fdf9254cd3fad3b08c9b371b7e8d8c87056d058fade7dae6d54fbbf335ebbcf7224f0e940464d0ca8f36429c0c2718940980dfe5cd6e7e345d1d1dc859db7ad3a77a849a130eba629a110aba480c250f7ed531339a930481eeb568f4fe34f1f344a8b8c4838ccc170ccf30eb8f2d7e65e5972220581c55190989ba5849a44352bb74b8e33c9ddd7ddef42b210e38ba6daa1b887852eb0beaaeee2844abefdb3d79ed9112f6ef43a52d2ff0bfda7830db49aaa08ae1fb9e012a013341417836c0432fac868dfb6663a52e998c037883c17b2a799db80df06036e0bde3008fc181de2fb1bca9e5cfee9cb0e43f42ac7867ee9913270a316fc347b316b869f41df1003f68c8fb84491ca4b262de2adc8b8a9e0337dedaa374f868f44482810705cec0cfe62f0ff07c84049c455220a0311572b5e19dfd2499004171d773ac2dd779ef36d9d13edb85e8d4bff7c45b8f93cfa6349b7dd25d09df1d56ef6ea4d7958111e0eb7973b8e483896592d9bfe98d4563c7aa5fd2018ac6622018949b099358a24a0725402e8920216964c474b430f1f3bed433d846c28504050809d9c0b8ea88db401ed09fe384019faf636d7e11192794bcdfbe6cb98ef895965f9a808455e5db70701422e7950a3611748f4c3f1b6a20204d58ed66b76d1fca38b6dd22218ebd7ac0ca6b5e17a2e5e96dbebea052c2fe38e5cd56d76b38d80a074b3f3083365e26f3ea1a0c9ca07923db002ff1c18f5e35681c35d9364c07bf4f05e56b3b0c9e0df0d4f7a05a6bc0ed1302fe40e2428ef4b19a9ea512e3ad9ffc9839e32c218a2f9b79fd74f98bb5cdbfbf7f03dce4176157c6e2c153fba3aa310090a7a9f6a5b166c9e3f84155cb6e1c347a55617b5fa9046c55914a0bf6194a22b4aed1c88e5e88404888419aadd74de5e77dcf1ff8e619723c0f4b3d6ade2d9240a786d29b76a98e7bb78971e15e7f06e378dc7a89fdbeaa7877c6f24385f8f0af2fbcf7d0003987436b3f22f767640018c1e7354a8475ccbb881376ce69277dd5aac37e8f6d4e4870fe1921a9e777e1f7d7db51d6f6d559ec775c1565221836c3b7b1aad35fbcfcd204048bad2ada700ed4209c23c7461b0f75caff50751ab8ffa69fa36abef15cf7e096d7b4296bdd5d88eeb3fbbdd2e72a213a0ce8f2e4f9e7cb4df942cb97dcaca9a11742e9cd9b37a8ca11f1d8c5490ce3e1533cf88be27e9dc87dd70178d90c5e36c073e0536d63d3c1efb36518085631b47b1a545c49aaa0eaff50bfcee520abca77b75c2125c1d259eb87cf6d21c4bacb8bc38bda09b1b2fe9bc37f7073419d1c9d100952013077c71a20e4d518498e5e2aa60389130ae6868b1ca2cf5f9e7174fb4d97eca88aac6d7f56750ae43e42552d7921028344eb1925136cc7ad6bab87f559b3c992efb8b17fc7e3e43ee8d0a1736d7fd9df961fb69978861ce7d4caf45d47ac4e5e051ab7de62a742746474b4eb7cf0e584ff5e7aeb07426cbc7ed588cd2079d432af218a6b401b15c63540bb0a02e55045c9bd8be88a602d8d6123ca70f63bd6364a24cc1642073c12166e8b40c26070f32655145799fdaf2118bcfc5a08081647557cc385e046ae14f0d622ef16e4e0b0c68d0684c5c7d1dd0e6dc829e3ba0ba7b6489bdd649610873f7ff42387ad10a26ddee157674889a5e9a52d7b1efcbc7cd79d69fd9a3f21eb05a9bd5db76271ae382d66244d17b70b298358d789d6966ba65e635d163357cfc4ce58eabf6fa31fbbbc9e351d7d73a01c27ee73793df97b554055261ea68d1d3b4e306f98f8a3a545c14868f00d40c88354227f1400d1528a93e9640c8d7d6e5d690d72554c91eeb52fbbc6ceba3135356e246cedef6aeeadb85b888a93767e503641884da135976ce821c44fafaf1ce0065445cba2371087851bcaa0cb454242e9f499b7091110943ce0ae7a327aa34a04dba7eb9f73a324e215015b0aa620f1795519541efbbc38aab2c01d3934186a201cb89e7d9209aab8205e240dd63512942693a18608658ca3727f77c83fbb7ed05eaecf76e7747a24a3408803fe79d0968e574bd80fa51f71e005f25d57a655bb0c53a87d685e6c9fac1617c5d6e36a71ad0b6377687b97b5f2bfafaa26f4f902c697e21ed046850404558ba86a646ed3e8d6ca0908a98ad841baa72a459f0462806bb2b9f822ba79cd0810ad2b0e2fcaf037e0f3db2fbf360282c55115b78dc091e88b64a774ed2099e0c6a30d88f524f81c2384e1ea5b4af3ce3842dcd0a87a203ca08d040efc9de880301d509e1403c54efcdc2f566cbda9df151827f2b31bfac81889124090dba3e1c6359e769d7bbb90b19271aef5f83ecc5d05d996f906ffc5c61bf0b0b6400d0c11caa674632632486c5d23e1f0a970e1c2b42613a1fd28fb1d3cc709145d5b10d26be6f6e071dc502301a13bb7d1c681b6282424a8620406006d56e4ccc024443a786df6fea8d8b3e2c0efb3d8e700df47580ceeb151ae5ae370b9e483bfe34e00765258ff064bea2f8d80a184551505fffb7a68a36da41e099f03356c083ad06003920a05366064a0aae9c22048934c04086be00029d0110906236016a45ba65c48904c11d2047a0707271c581219437fc1421bc881f69dd0fe5055f519f0f965d0462323777fc47187f18d407a6a1e7055cbef35b8873d87aa29ee1f8fb60d788e0e80c5806f0eb47f2dde2b8eaae8a081839a0e1a94111f60cfc37a8b02475f0f1c7e3decdb08ac331cdfda93549d066d92d4611e8880601be0e3bab6eed4d18ef685f7fd0dde8304e478a8e1fd35f03e5235a2c4c19c1de8aa55945819e72eee177b548c84e633f61caeef0758db81f619faf74420f0f3fefae7bef7ffeadc6cf775f9b54a2058d41546640be1b612baa0894b26c8713149220db262a68277174a22292c9091736c248120e140a328e0451120889f8960fc468a89e38a425aea7abcc9112513ee478fa91e78ae206ca36482de52dfb1e7b0662a325299e1c6e64671201ce2661dff5f5d715485f122dc7984d617974cd8ba4e05556c1aac677e711aad6b6088683da35718638cf8b50bf52c4e069d2188016092087762e0dffb22aa11be2db4b2c792475071003e974cd8f77cddfcff235134b6fcda090896b0aa9879db8b0076544d073c2728b86160a3a5409a6fdc70c499618dfefbb0517d2a2cdc70600c251516120e5b47ffd74a507c1b83d5dcaf9e0e6c6efb084a01c1b2dce24152f72c7c0e048908467ff67ee61f6f348a23e108881cffd594b0aa685ddbd0b6f49ae2499071428282eb783bb471fd1a6c2bb4aeb9ea0a094936c30f19049c4f1637c1bdaa7ca93d3070ee741d8e31cea1b1c56175234bd0faffbf12547e2b04841747559c83f3d94c70232201818d4784856d241fc1e01b0d37f4437a5b200119ccf0b493e9ccafa038ac86c28dcef5ff85cf17e9df932d020ffe00b7c7084b3181924994fbc9f33aace3f98bdb367eae1256156790b05f5c32a15429b85e0d0c135fbf21b6fe79c4bcc5ce036e1ce671124448b8a4c9920e22e1f125a774f4cff7f8e076f6f2f7ff57f6b0fc56090816aee2823679baf7841a0f7eb8e8c5ba03da904f9f36144814a1f17a9b366e2fd606b74a52619da2a3479fffca4b14dc33c558f6c538fdfb285c901385c0309f3be42068ff57afebc71a3e8700d1e8013a1cb26160bb98e1395cfffc7f5de10c098c0724bbf1d61facf310ae532619a3b797f51eb4c71bbe5f92f8bd34efc83030b757f2765bc83e8775500fb632b84d9f728b91ca2a47fc5ff94d97ff170000fffff898dda83e6a16740000000049454e44ae426082', 'image/png'); +UPDATE PRODUCT set PICTUREID=10; diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql new file mode 100644 index 000000000..980d37d43 --- /dev/null +++ b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql @@ -0,0 +1,81 @@ +-- Autogenerated: do not edit this file + +CREATE TABLE BATCH_JOB_INSTANCE ( + JOB_INSTANCE_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_NAME VARCHAR(100) NOT NULL, + JOB_KEY VARCHAR(32) NOT NULL, + constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION ( + JOB_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_INSTANCE_ID BIGINT NOT NULL, + CREATE_TIME TIMESTAMP NOT NULL, + START_TIME TIMESTAMP DEFAULT NULL , + END_TIME TIMESTAMP DEFAULT NULL , + STATUS VARCHAR(10) , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED TIMESTAMP, + JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL, + constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) + references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION_PARAMS ( + JOB_EXECUTION_ID BIGINT NOT NULL , + TYPE_CD VARCHAR(6) NOT NULL , + KEY_NAME VARCHAR(100) NOT NULL , + STRING_VAL VARCHAR(250) , + DATE_VAL TIMESTAMP DEFAULT NULL , + LONG_VAL BIGINT , + DOUBLE_VAL DOUBLE PRECISION , + IDENTIFYING CHAR(1) NOT NULL , + constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_STEP_EXECUTION ( + STEP_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , + VERSION BIGINT NOT NULL, + STEP_NAME VARCHAR(100) NOT NULL, + JOB_EXECUTION_ID BIGINT NOT NULL, + START_TIME TIMESTAMP NOT NULL , + END_TIME TIMESTAMP DEFAULT NULL , + STATUS VARCHAR(10) , + COMMIT_COUNT BIGINT , + READ_COUNT BIGINT , + FILTER_COUNT BIGINT , + WRITE_COUNT BIGINT , + READ_SKIP_COUNT BIGINT , + WRITE_SKIP_COUNT BIGINT , + PROCESS_SKIP_COUNT BIGINT , + ROLLBACK_COUNT BIGINT , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED TIMESTAMP, + constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT ( + STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT LONGVARCHAR , + constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) + references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID) +) ; + +CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT ( + JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT LONGVARCHAR , + constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ; + +CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ; +CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ; +CREATE SEQUENCE BATCH_JOB_SEQ; diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql new file mode 100644 index 000000000..f34cc3507 --- /dev/null +++ b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql @@ -0,0 +1,132 @@ +-- This is the SQL script for setting up the DDL for the h2 database +-- In a typical project you would only distinguish between main and test for flyway SQLs +-- However, in this sample application we provde support for multiple databases in parallel +-- You can simply choose the DB of your choice by setting spring.profiles.active=XXX in config/application.properties +-- Assuming that the preconfigured user exists with according credentials using the included SQLs + +CREATE SEQUENCE HIBERNATE_SEQUENCE START WITH 1000000; + +-- *** Staffmemeber *** +CREATE TABLE STAFFMEMBER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + firstname VARCHAR(255), + lastname VARCHAR(255), + login VARCHAR(255), + role INTEGER +); +ALTER TABLE STAFFMEMBER ADD CONSTRAINT PK_STAFFMEMEBER PRIMARY KEY(id); +ALTER TABLE STAFFMEMBER ADD CONSTRAINT UC_STAFFMEMBER_LOGIN UNIQUE(login); + +-- *** Product *** +CREATE TABLE PRODUCT( + dtype VARCHAR(31) NOT NULL, + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + description VARCHAR(255), + name VARCHAR(255), + alcoholic BOOLEAN, + pictureId BIGINT +); +ALTER TABLE PRODUCT ADD CONSTRAINT PK_PRODUCT PRIMARY KEY(id); +CREATE TABLE PRODUCT_AUD( + revtype TINYINT, + description VARCHAR(255), + name VARCHAR(255), + pictureId BIGINT, + alcoholic BOOLEAN, + dtype VARCHAR(31) NOT NULL, + id BIGINT NOT NULL, + rev BIGINT NOT NULL +); + +-- *** Offer *** +CREATE TABLE OFFER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + description VARCHAR(255), + name VARCHAR(255), + price DECIMAL(19, 2), + number BIGINT, + state INTEGER, + drink_id BIGINT, + meal_id BIGINT, + sideDish_id BIGINT +); +ALTER TABLE OFFER ADD CONSTRAINT PK_OFFER PRIMARY KEY(id); +ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NAME UNIQUE(name); +ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NUMBER UNIQUE(number); +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2SIDEDISH FOREIGN KEY(sideDish_id) REFERENCES PRODUCT(id) NOCHECK; +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2MEAL FOREIGN KEY(meal_id) REFERENCES PRODUCT(id) NOCHECK; +ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2DRINK FOREIGN KEY(drink_id) REFERENCES PRODUCT(id) NOCHECK; + +-- *** RestaurantTable (Table is a reserved keyword in Oracle) *** +CREATE TABLE RESTAURANTTABLE( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + number BIGINT NOT NULL CHECK (NUMBER >= 0), + state INTEGER, + waiter_id BIGINT +); +ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT PK_RESTAURANTTABLE PRIMARY KEY(id); +ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT UC_TABLE_NUMBER UNIQUE(number); + +-- *** RestaurantOrder (Order is a reserved keyword in Oracle) *** +CREATE TABLE RESTAURANTORDER( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + state INTEGER, + table_id BIGINT NOT NULL +); +ALTER TABLE RESTAURANTORDER ADD CONSTRAINT PK_RESTAURANTORDER PRIMARY KEY(id); + +-- *** OrderPosition *** +CREATE TABLE ORDERPOSITION( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + comment VARCHAR(255), + cook_id BIGINT, + offer_id BIGINT, + offerName VARCHAR(255), + price DECIMAL(19, 2), + state INTEGER, + drinkState INTEGER, + order_id BIGINT +); +ALTER TABLE ORDERPOSITION ADD CONSTRAINT PK_ORDERPOSITON PRIMARY KEY(id); +ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2ORDER FOREIGN KEY(order_id) REFERENCES RESTAURANTORDER(id) NOCHECK; +ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2COOK FOREIGN KEY(cook_id) REFERENCES STAFFMEMBER(id) NOCHECK; + +-- *** Bill *** +CREATE TABLE BILL( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + payed BOOLEAN NOT NULL, + tip DECIMAL(19, 2), + total DECIMAL(19, 2) +); +ALTER TABLE BILL ADD CONSTRAINT PK_BILL PRIMARY KEY(id); +CREATE TABLE BILL_ORDERPOSITION( + bill_id BIGINT NOT NULL, + orderpositions_id BIGINT NOT NULL +); +ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2BILL FOREIGN KEY(bill_id) REFERENCES BILL(id) NOCHECK; +ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2ORDPOS FOREIGN KEY(orderPositions_ID) REFERENCES ORDERPOSITION(id) NOCHECK; + +-- *** BinaryObject (BLOBs) *** +CREATE TABLE BINARYOBJECT ( + id BIGINT NOT NULL, + modificationCounter INTEGER NOT NULL, + data BLOB(2147483647), + size BIGINT NOT NULL, + mimetype VARCHAR(255), + PRIMARY KEY (ID) +); + +-- *** RevInfo (Commit log for envers audit trail) *** +CREATE TABLE REVINFO( + id BIGINT NOT NULL generated by default as identity (start with 1), + timestamp BIGINT NOT NULL, + user VARCHAR(255) +); + diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-server/src/main/webapp/index.jsp b/templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/archetype-resources/__rootArtifactId__-server/src/main/webapp/index.jsp rename to templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp diff --git a/oasp4j-templates/oasp4j-template-server/src/main/resources/pom.xml b/templates/server/src/main/resources/pom.xml similarity index 98% rename from oasp4j-templates/oasp4j-template-server/src/main/resources/pom.xml rename to templates/server/src/main/resources/pom.xml index 8e7d607cd..15ad71c4c 100644 --- a/oasp4j-templates/oasp4j-template-server/src/main/resources/pom.xml +++ b/templates/server/src/main/resources/pom.xml @@ -18,11 +18,11 @@ - ${artifactId}-core + core #if($earProjectName != '.') ${earProjectName} #end - ${artifactId}-server + server diff --git a/oasp4j-templates/oasp4j-template-server/src/test/resources/projects/basic/archetype.properties b/templates/server/src/test/resources/projects/basic/archetype.properties similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/test/resources/projects/basic/archetype.properties rename to templates/server/src/test/resources/projects/basic/archetype.properties diff --git a/oasp4j-templates/oasp4j-template-server/src/test/resources/projects/basic/goal.txt b/templates/server/src/test/resources/projects/basic/goal.txt similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/test/resources/projects/basic/goal.txt rename to templates/server/src/test/resources/projects/basic/goal.txt diff --git a/oasp4j-templates/oasp4j-template-server/src/test/resources/projects/enterprise/archetype.properties b/templates/server/src/test/resources/projects/enterprise/archetype.properties similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/test/resources/projects/enterprise/archetype.properties rename to templates/server/src/test/resources/projects/enterprise/archetype.properties diff --git a/oasp4j-templates/oasp4j-template-server/src/test/resources/projects/enterprise/goal.txt b/templates/server/src/test/resources/projects/enterprise/goal.txt similarity index 100% rename from oasp4j-templates/oasp4j-template-server/src/test/resources/projects/enterprise/goal.txt rename to templates/server/src/test/resources/projects/enterprise/goal.txt diff --git a/wiki b/wiki deleted file mode 160000 index 0aff9f22a..000000000 --- a/wiki +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0aff9f22a0519c7cca7db75737213fffec3bb339 From 6e89d492629e11aa779c284eef14df7a42ce9146 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Tue, 19 Jul 2016 09:15:24 +0200 Subject: [PATCH 14/18] #6 unnecessary modules + templates removed, which are not interesting for trainings --- modules/basic/pom.xml | 22 -- .../basic/common/api/to/AbstractCto.java | 27 -- .../basic/common/api/to/AbstractEto.java | 148 -------- .../basic/common/api/to/AbstractTo.java | 47 --- .../configuration/SpringProfileConstants.java | 44 --- modules/batch/pom.xml | 62 ---- .../base/SpringBootBatchCommandLine.java | 326 ------------------ .../common/impl/ChunkLoggingListener.java | 94 ----- ...cherWithAdditionalRestartCapabilities.java | 68 ---- .../base/NamedQueryFactoryBean.java | 65 ---- .../common/impl/PerformanceLogFilter.java | 122 ------- .../oasp/logging/logback/appender-console.xml | 8 - .../logging/logback/appender-file-debug.xml | 15 - .../logging/logback/appender-file-info.xml | 18 - .../logging/logback/appender-file-warn.xml | 18 - .../logging/logback/appenders-file-all.xml | 6 - .../logback/appenders-file-default.xml | 5 - .../logback/application-logging.properties | 8 - .../impl/json/AbstractJsonDeserializer.java | 127 ------- pom.xml | 1 - templates/pom.xml | 20 -- templates/server/build.xml | 185 ---------- templates/server/pom.xml | 122 ------- .../META-INF/maven/archetype-metadata.xml | 87 ----- .../__earProjectName__/pom.xml | 24 -- .../logic/impl/UsermanagementDummyImpl.java | 31 -- .../config/app/dataaccess/NamedQueries.xml | 5 - .../db/migration/V0002__R001_Master_data.sql | 47 --- .../V0003__R001_Add_blob_table_and_data.sql | 2 - .../V0004__R001_Add_batch_tables.sql | 81 ----- .../h2/V0001__R001_Create_schema.sql | 132 ------- .../server/src/main/webapp/index.jsp | 3 - templates/server/src/main/resources/pom.xml | 167 --------- .../projects/basic/archetype.properties | 6 - .../test/resources/projects/basic/goal.txt | 1 - .../projects/enterprise/archetype.properties | 6 - .../resources/projects/enterprise/goal.txt | 1 - 37 files changed, 2151 deletions(-) delete mode 100644 modules/basic/pom.xml delete mode 100644 modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractCto.java delete mode 100644 modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractEto.java delete mode 100644 modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractTo.java delete mode 100644 modules/basic/src/main/java/io/oasp/module/basic/configuration/SpringProfileConstants.java delete mode 100644 modules/batch/pom.xml delete mode 100644 modules/batch/src/main/java/io/oasp/module/batch/common/base/SpringBootBatchCommandLine.java delete mode 100644 modules/batch/src/main/java/io/oasp/module/batch/common/impl/ChunkLoggingListener.java delete mode 100644 modules/batch/src/main/java/io/oasp/module/batch/common/impl/JobLauncherWithAdditionalRestartCapabilities.java delete mode 100644 modules/jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/NamedQueryFactoryBean.java delete mode 100644 modules/logging/src/main/java/io/oasp/module/logging/common/impl/PerformanceLogFilter.java delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appender-console.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-debug.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-info.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-warn.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-all.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-default.xml delete mode 100644 modules/logging/src/main/resources/io/oasp/logging/logback/application-logging.properties delete mode 100644 modules/rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java delete mode 100644 templates/pom.xml delete mode 100644 templates/server/build.xml delete mode 100644 templates/server/pom.xml delete mode 100644 templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml delete mode 100644 templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql delete mode 100644 templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql delete mode 100644 templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp delete mode 100644 templates/server/src/main/resources/pom.xml delete mode 100644 templates/server/src/test/resources/projects/basic/archetype.properties delete mode 100644 templates/server/src/test/resources/projects/basic/goal.txt delete mode 100644 templates/server/src/test/resources/projects/enterprise/archetype.properties delete mode 100644 templates/server/src/test/resources/projects/enterprise/goal.txt diff --git a/modules/basic/pom.xml b/modules/basic/pom.xml deleted file mode 100644 index f562fd0f7..000000000 --- a/modules/basic/pom.xml +++ /dev/null @@ -1,22 +0,0 @@ - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - - io.oasp.java.modules - oasp4j-basic - ${oasp4j.version} - jar - ${project.artifactId} - mmm-util-core based infrastructure for entities of the Open Application Standard Platform for Java (OASP4J). - - - - net.sf.m-m-m - mmm-util-core - - - \ No newline at end of file diff --git a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractCto.java b/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractCto.java deleted file mode 100644 index ba4947dd5..000000000 --- a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractCto.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.oasp.module.basic.common.api.to; - -import net.sf.mmm.util.transferobject.api.AbstractTransferObject; -import net.sf.mmm.util.transferobject.api.TransferObject; - -/** - * This is the abstract base class for a composite {@link AbstractTo transfer-object}. Such object should contain - * (aggregate) other {@link AbstractTransferObject}s but no atomic data. This means it has properties that contain a - * {@link TransferObject} or a {@link java.util.Collection} of those but no {@link net.sf.mmm.util.lang.api.Datatype - * values}.
- * Classes extending this class should carry the suffix Cto. - * - * @author hohwille - */ -public abstract class AbstractCto extends AbstractTo { - - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AbstractCto() { - - super(); - } - -} diff --git a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractEto.java b/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractEto.java deleted file mode 100644 index d098db82f..000000000 --- a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractEto.java +++ /dev/null @@ -1,148 +0,0 @@ -package io.oasp.module.basic.common.api.to; - -import net.sf.mmm.util.entity.api.GenericEntity; -import net.sf.mmm.util.entity.api.MutableRevisionedEntity; -import net.sf.mmm.util.entity.api.PersistenceEntity; -import net.sf.mmm.util.transferobject.api.TransferObject; - -/** - * This is the abstract base class for an {@link TransferObject} that only contains data without relations. This is - * called DTO (data transfer object). Here data means properties that typically represent a - * {@link net.sf.mmm.util.lang.api.Datatype} and potentially for relations the ID (as {@link Long}). For actual - * relations you will use {@link AbstractCto CTO}s to express what set of entities to transfer, load, save, update, etc. - * without redundancies. It typically corresponds to an {@link net.sf.mmm.util.entity.api.GenericEntity entity}. For - * additional details and an example consult the {@link net.sf.mmm.util.transferobject.api package JavaDoc}. - * - * @author hohwille - * @author erandres - */ -public abstract class AbstractEto extends AbstractTo implements MutableRevisionedEntity { - - private static final long serialVersionUID = 1L; - - /** @see #getId() */ - private Long id; - - /** @see #getModificationCounter() */ - private int modificationCounter; - - /** @see #getRevision() */ - private Number revision; - - /** - * @see #getModificationCounter() - */ - private transient GenericEntity persistentEntity; - - /** - * The constructor. - */ - public AbstractEto() { - - super(); - this.revision = LATEST_REVISION; - } - - /** - * {@inheritDoc} - */ - @Override - public Long getId() { - - return this.id; - } - - /** - * {@inheritDoc} - */ - @Override - public void setId(Long id) { - - this.id = id; - } - - /** - * {@inheritDoc} - */ - @Override - public int getModificationCounter() { - - if (this.persistentEntity != null) { - // JPA implementations will update modification counter only after the transaction has been committed. - // Conversion will typically happen before and would result in the wrong (old) modification counter. - // Therefore we update the modification counter here (that has to be called before serialization takes - // place). - this.modificationCounter = this.persistentEntity.getModificationCounter(); - } - return this.modificationCounter; - } - - /** - * {@inheritDoc} - */ - @Override - public void setModificationCounter(int version) { - - this.modificationCounter = version; - } - - /** - * {@inheritDoc} - */ - @Override - public Number getRevision() { - - return this.revision; - } - - /** - * {@inheritDoc} - */ - @Override - public void setRevision(Number revision) { - - this.revision = revision; - } - - /** - * Method to extend {@link #toString()} logic. - * - * @param buffer is the {@link StringBuilder} where to {@link StringBuilder#append(Object) append} the string - * representation. - */ - @Override - protected void toString(StringBuilder buffer) { - - super.toString(buffer); - if (this.id != null) { - buffer.append("[id="); - buffer.append(this.id); - buffer.append("]"); - } - if (this.revision != null) { - buffer.append("[rev="); - buffer.append(this.revision); - buffer.append("]"); - } - } - - /** - * Inner class to grant access to internal {@link PersistenceEntity} reference of an {@link AbstractEto}. Shall only - * be used internally and never be external users. - */ - public static class PersistentEntityAccess { - - /** - * Sets the internal {@link PersistenceEntity} reference of the given {@link AbstractEto}. - * - * @param is the generic type of the {@link GenericEntity#getId() ID}. - * @param eto is the {@link AbstractEto}. - * @param persistentEntity is the {@link PersistenceEntity}. - */ - protected void setPersistentEntity(AbstractEto eto, PersistenceEntity persistentEntity) { - - assert ((eto.persistentEntity == null) || (persistentEntity == null)); - eto.persistentEntity = persistentEntity; - } - } -} diff --git a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractTo.java b/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractTo.java deleted file mode 100644 index 1d29a3f96..000000000 --- a/modules/basic/src/main/java/io/oasp/module/basic/common/api/to/AbstractTo.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.oasp.module.basic.common.api.to; - -import net.sf.mmm.util.transferobject.api.TransferObject; - -/** - * Abstract class for a plain {@link net.sf.mmm.util.transferobject.api.TransferObject} that is neither a - * {@link AbstractEto ETO} nor a {@link AbstractCto CTO}. Classes extending this class should carry the suffix - * Cto.
- * - * @author hohwille - */ -public abstract class AbstractTo implements TransferObject { - - /** UID for serialization. */ - private static final long serialVersionUID = 1L; - - /** - * The constructor. - */ - public AbstractTo() { - - super(); - } - - /** - * {@inheritDoc} - */ - @Override - public final String toString() { - - StringBuilder buffer = new StringBuilder(); - toString(buffer); - return buffer.toString(); - } - - /** - * Method to extend {@link #toString()} logic. Override to add additional information. - * - * @param buffer is the {@link StringBuilder} where to {@link StringBuilder#append(Object) append} the string - * representation. - */ - protected void toString(StringBuilder buffer) { - - buffer.append(getClass().getSimpleName()); - } - -} diff --git a/modules/basic/src/main/java/io/oasp/module/basic/configuration/SpringProfileConstants.java b/modules/basic/src/main/java/io/oasp/module/basic/configuration/SpringProfileConstants.java deleted file mode 100644 index 0d4c48174..000000000 --- a/modules/basic/src/main/java/io/oasp/module/basic/configuration/SpringProfileConstants.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.oasp.module.basic.configuration; - -/** - * This class provides {@code String} constants which allow to distinguish several bean definition profiles. The - * constants should be used in {@code @Profile} annotations to avoid multiple points of failure (e.g., through typos - * within annotations).
- * In test scenarios, these constants should be used in conjunction with the {@code @ActiveProfile} annotation. - * - * @author jmolinar - * @since 2.1.0 - */ -public class SpringProfileConstants { - - /** - * This constant applies to all tests. - */ - public static final String JUNIT = "junit"; - - /** - * This constant denotes a live profile. - */ - public static final String NOT_JUNIT = "!" + JUNIT; - - /** - * This constant should be used in conjunction with component tests. - */ - public static final String COMPONENT_TEST = "component-test"; - - /** - * This constant should be used in conjunction with module tests. - */ - public static final String MODULE_TEST = "module-test"; - - /** - * This constant should be used in conjunction with subsystem tests. - */ - public static final String SUBSYSTEM_TEST = "subsystem-test"; - - /** - * This constant should be used in conjunction with system tests. - */ - public static final String SYSTEM_TEST = "system-test"; - -} diff --git a/modules/batch/pom.xml b/modules/batch/pom.xml deleted file mode 100644 index 4aa6d2ea8..000000000 --- a/modules/batch/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - 4.0.0 - - io.oasp.java.dev - oasp4j-modules - dev-SNAPSHOT - - - io.oasp.java.modules - oasp4j-batch - ${oasp4j.version} - jar - ${project.artifactId} - Batch infrastructure of the Open Application Standard Platform for Java (OASP4J). - - - - - io.oasp.java.modules - oasp4j-jpa - - - io.oasp.java.modules - oasp4j-logging - - - - - - org.springframework.batch - spring-batch-core - - - org.springframework.batch - spring-batch-infrastructure - - - org.springframework.batch - spring-batch-integration - - - - - org.springframework.boot - spring-boot - true - - - - - org.springframework.batch - spring-batch-test - test - - - io.oasp.java.modules - oasp4j-test - test - - - diff --git a/modules/batch/src/main/java/io/oasp/module/batch/common/base/SpringBootBatchCommandLine.java b/modules/batch/src/main/java/io/oasp/module/batch/common/base/SpringBootBatchCommandLine.java deleted file mode 100644 index c934c1b28..000000000 --- a/modules/batch/src/main/java/io/oasp/module/batch/common/base/SpringBootBatchCommandLine.java +++ /dev/null @@ -1,326 +0,0 @@ -package io.oasp.module.batch.common.base; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.configuration.JobLocator; -import org.springframework.batch.core.converter.DefaultJobParametersConverter; -import org.springframework.batch.core.converter.JobParametersConverter; -import org.springframework.batch.core.launch.JobExecutionNotRunningException; -import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.JobOperator; -import org.springframework.batch.core.launch.support.CommandLineJobRunner; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.ExitCodeGenerator; -import org.springframework.boot.SpringApplication; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.StringUtils; - -/** - * Launcher for launching batch jobs from the command line when Spring Boot is - * used. Similar to the {@link CommandLineJobRunner}, which does not work very - * well with Spring Boot. - *

- * Do not use this class if Spring Boot is not used! - *

- * It expects the full class name of the Spring Boot configuration class to be - * used as first argument, the class/XML file for configuring the job as second - * argument and the job name as third.
- * Moreover parameters can be specified as further arguments (convention: - * key1=value1 key2=value2 ...). - *

- * Example:
- * java io.oasp.module.batch.common.base.SpringBootBatchCommandLine - * io.oasp.gastronomy.restaurant.SpringBootBatchApp - * classpath:config/app/batch/beans-productimport.xml productImportJob - * drinks.file=file:import/drinks.csv date(date)=2015/12/20 - *

- * For stopping all running executions of a job, use the -stop option. - *

- * Example:
- * java io.oasp.module.batch.common.base.SpringBootBatchCommandLine - * io.oasp.gastronomy.restaurant.SpringBootBatchApp - * classpath:config/app/batch/beans-productimport.xml productImportJob -stop - * - * @author Ludger Overbeck - * - */ -public class SpringBootBatchCommandLine { - - private static final Logger LOG = LoggerFactory - .getLogger(SpringBootBatchCommandLine.class); - - private ResourceLoader resourceLoader = new DefaultResourceLoader(); - - public static enum Operation { - START, STOP - }; - - private JobLauncher launcher; - - private JobLocator locator; - - private JobParametersConverter parametersConverter; - - private JobOperator operator; - - public static void main(String[] args) throws Exception { - - if (args.length < 3) { - - handleIncorrectParameters(); - return; - } - - List configurations = new ArrayList(2); - configurations.add(args[0]); - configurations.add(args[1]); - - List parameters = new ArrayList(); - - Operation op = Operation.START; - if (args.length > 3 && args[3].equalsIgnoreCase("-stop")) { - - if (args.length > 4) { - - handleIncorrectParameters(); - return; - } - - op = Operation.STOP; - } else { - - for (int i = 3; i < args.length; i++) { - - parameters.add(args[i]); - } - } - - new SpringBootBatchCommandLine().execute(op, configurations, args[2], - parameters); - } - - private static void handleIncorrectParameters() { - - LOG.error("Incorrect parameters."); - LOG.info("Usage:"); - LOG.info("java io.oasp.module.batch.common.base.SpringBootBatchCommandLine" - + " " - + " param1=value1 param2=value2 ..."); - LOG.info("For stopping all running executions of a batch job:"); - LOG.info("java io.oasp.module.batch.common.base.BatchCommandLine" - + " " - + " -stop"); - LOG.info("Example:"); - LOG.info("java io.oasp.module.batch.common.base.SpringBootBatchCommandLine" - + " io.oasp.gastronomy.restaurant.SpringBootBatchApp" - + " classpath:config/app/batch/beans-productimport.xml" - + " productImportJob drinks.file=file:import/drinks.csv" - + " date(date)=2015/12/20"); - } - - protected int getReturnCode(JobExecution jobExecution) { - - if (jobExecution.getStatus() != null - && jobExecution.getStatus() == BatchStatus.COMPLETED) - return 0; - else - return 1; - } - - private Object getConfiguration(String stringRepresentation) { - - // try to load a source of Spring bean definitions: - // 1. try to load it as a (JavaConfig) class - // 2. if that fails: try to load it as XML resource - - try { - - return Class.forName(stringRepresentation); - } catch (ClassNotFoundException e) { - - return resourceLoader.getResource(stringRepresentation); - } - } - - private void findBeans(ConfigurableApplicationContext ctx) { - - launcher = ctx.getBean(JobLauncher.class); - locator = ctx.getBean(JobLocator.class); // supertype of JobRegistry - operator = ctx.getBean(JobOperator.class); - try { - - parametersConverter = ctx.getBean(JobParametersConverter.class); - } catch (NoSuchBeanDefinitionException e) { - - parametersConverter = new DefaultJobParametersConverter(); - } - } - - /** - * Initialize the application context and execute the operation. - *

- * The application context is closed after the operation has finished. - * - * @param operation - * The operation to start. - * @param configurations - * The sources of bean configurations (either JavaConfig classes - * or XML files). - * @param jobName - * The name of the job to launch/stop. - * @param parameters - * The parameters (key=value). - * @throws Exception - */ - public void execute(Operation operation, List configurations, - String jobName, List parameters) throws Exception { - - // get sources of configuration - Object[] configurationObjects = new Object[configurations.size()]; - for (int i = 0; i < configurations.size(); i++) { - - configurationObjects[i] = getConfiguration(configurations.get(i)); - } - - SpringApplication app = new SpringApplication(configurationObjects); - - // no (web) server needed - app.setWebEnvironment(false); - - // start the application - ConfigurableApplicationContext ctx = app.run(new String[0]); - - switch (operation) { - case START: - startBatch(ctx, jobName, parameters); - break; - case STOP: - stopBatch(ctx, jobName); - break; - default: - throw new RuntimeException("Unknown operation: " + operation); - } - - } - - private void startBatch(ConfigurableApplicationContext ctx, String jobName, - List parameters) throws Exception { - - JobExecution jobExecution = null; - try { - - findBeans(ctx); - - JobParameters params = parametersConverter - .getJobParameters(StringUtils - .splitArrayElementsIntoProperties( - parameters.toArray(new String[] {}), "=")); - - // execute the batch - // the JobOperator would require special logic for a restart, so we - // are using the JobLauncher directly here - jobExecution = launcher.run(locator.getJob(jobName), params); - - } finally { - - // evaluate the outcome - final int returnCode = (jobExecution == null) ? 1 - : getReturnCode(jobExecution); - if (jobExecution == null) { - - LOG.error("Batch Status: Batch could not be started."); - } else { - - LOG.info("Batch start time: {}", - jobExecution.getStartTime() == null ? "null" - : jobExecution.getStartTime()); - LOG.info("Batch end time: {}", - jobExecution.getEndTime() == null ? "null" - : jobExecution.getEndTime()); - - if (returnCode == 0) { - - LOG.info("Batch Status: {}", - jobExecution.getStatus() == null ? "null" - : jobExecution.getStatus()); - } else { - - LOG.error("Batch Status: {}", - jobExecution.getStatus() == null ? "null" - : jobExecution.getStatus()); - } - } - LOG.info("Return Code: {}", returnCode); - - SpringApplication.exit(ctx, new ExitCodeGenerator() { - - @Override - public int getExitCode() { - return returnCode; - } - }); - } - } - - private void stopBatch(ConfigurableApplicationContext ctx, String jobName) - throws Exception { - - int returnCode = 0; - try { - - findBeans(ctx); - - Set runningJobExecutionIDs = operator - .getRunningExecutions(jobName); - if (runningJobExecutionIDs.isEmpty()) { - - throw new JobExecutionNotRunningException("Batch job " - + jobName + " is currently not being executed."); - } - - LOG.debug("Found {} executions to be stopped (potentially" - + " already in state stopping).", - runningJobExecutionIDs.size()); - - int stoppedCount = 0; - for (Long id : runningJobExecutionIDs) { - - try { - - operator.stop(id); - stoppedCount++; - } catch (JobExecutionNotRunningException e) { - - // might have finished at this point - // or was in state stopping already - } - } - - LOG.info("Actually stopped {} batch executions.", stoppedCount); - - } catch (Exception e) { - - returnCode = 1; - throw e; - } finally { - - final int returnCodeResult = returnCode; - SpringApplication.exit(ctx, new ExitCodeGenerator() { - - @Override - public int getExitCode() { - return returnCodeResult; - } - }); - } - } -} diff --git a/modules/batch/src/main/java/io/oasp/module/batch/common/impl/ChunkLoggingListener.java b/modules/batch/src/main/java/io/oasp/module/batch/common/impl/ChunkLoggingListener.java deleted file mode 100644 index 16008e079..000000000 --- a/modules/batch/src/main/java/io/oasp/module/batch/common/impl/ChunkLoggingListener.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.oasp.module.batch.common.impl; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.batch.core.ItemProcessListener; -import org.springframework.batch.core.ItemReadListener; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.SkipListener; - -/** - * Spring Batch listener that logs exceptions together with the item(s) being processed at the time the exceptions - * occurred. - * - * @author Ludger Overbeck - */ -public class ChunkLoggingListener implements SkipListener, ItemReadListener, ItemProcessListener, - ItemWriteListener { - - private static final Logger LOG = LoggerFactory.getLogger(ChunkLoggingListener.class); - - protected String itemToString(Object item) { - - return item.toString(); - } - - @Override - public void onReadError(Exception e) { - - LOG.error("Failed to read item.", e); - } - - @Override - public void onProcessError(T item, Exception e) { - - LOG.error("Failed to process item: " + itemToString(item), e); - } - - @Override - public void onWriteError(Exception e, List items) { - - LOG.error("Failed to write items: " + itemToString(items), e); - } - - @Override - public void onSkipInRead(Throwable t) { - - LOG.warn("Skipped item in read.", t); - } - - @Override - public void onSkipInProcess(T item, Throwable t) { - - LOG.warn("Skipped item in process: " + itemToString(item), t); - } - - @Override - public void onSkipInWrite(S item, Throwable t) { - - LOG.warn("Skipped item in write: " + itemToString(item), t); - } - - @Override - public void beforeRead() { - - } - - @Override - public void afterRead(T item) { - - } - - @Override - public void beforeProcess(T item) { - - } - - @Override - public void afterProcess(T item, S result) { - - } - - @Override - public void beforeWrite(List items) { - - } - - @Override - public void afterWrite(List items) { - - } - -} \ No newline at end of file diff --git a/modules/batch/src/main/java/io/oasp/module/batch/common/impl/JobLauncherWithAdditionalRestartCapabilities.java b/modules/batch/src/main/java/io/oasp/module/batch/common/impl/JobLauncherWithAdditionalRestartCapabilities.java deleted file mode 100644 index 501e5cdbd..000000000 --- a/modules/batch/src/main/java/io/oasp/module/batch/common/impl/JobLauncherWithAdditionalRestartCapabilities.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.oasp.module.batch.common.impl; - -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.JobParametersIncrementer; -import org.springframework.batch.core.JobParametersInvalidException; -import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.support.SimpleJobLauncher; -import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; -import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.repository.JobRestartException; - -/** - * {@link JobLauncher} that extends the functionality provided by the standard {@link SimpleJobLauncher}: - *

- * For batches, which always restart from scratch (i.e. those marked with restartable="false"), the parameter's are - * 'incremented' automatically using the {@link JobParametersIncrementer} from the job (usually by adding or modifying - * the 'run.id' parameter). It is actually just a convenience functionality so that the one starting batches does not - * have to change the parameters manually. - * - * @author Ludger Overbeck - */ -public class JobLauncherWithAdditionalRestartCapabilities extends SimpleJobLauncher { - - private JobRepository jobRepository; - - @Override - public JobExecution run(final Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, - JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException { - - if (!job.isRestartable()) { - - JobParameters originalParameters = jobParameters; - while (this.jobRepository.isJobInstanceExists(job.getName(), jobParameters)) { - - // check if batch job is still running or was completed already - // analogous to SimpleJobRepository#createJobExecution - JobExecution jobExecution = this.jobRepository.getLastJobExecution(job.getName(), jobParameters); - if (jobExecution.isRunning()) { - throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: " - + jobExecution.getJobInstance()); - } - BatchStatus status = jobExecution.getStatus(); - if (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED) { - throw new JobInstanceAlreadyCompleteException("A job instance already exists and is complete for parameters=" - + originalParameters + ". If you want to run this job again, change the parameters."); - } - - // if there is a NullPointerException executing the following statement - // there has not been a JobParametersIncrementer set for the job - jobParameters = job.getJobParametersIncrementer().getNext(jobParameters); - } - } - - return super.run(job, jobParameters); - } - - @Override - public void setJobRepository(JobRepository jobRepository) { - - super.setJobRepository(jobRepository); - this.jobRepository = jobRepository; - } - -} diff --git a/modules/jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/NamedQueryFactoryBean.java b/modules/jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/NamedQueryFactoryBean.java deleted file mode 100644 index 0413851c1..000000000 --- a/modules/jpa/src/main/java/io/oasp/module/jpa/dataaccess/base/NamedQueryFactoryBean.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.oasp.module.jpa.dataaccess.base; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import org.hibernate.Query; -import org.springframework.beans.factory.FactoryBean; - -/** - * ProductWriter allows to get named query from resource NamedQueries.xml. - * It is used for example in job to get sql for JdbcCursorItemReader. - * - * @author ABIELEWI - */ -public class NamedQueryFactoryBean implements FactoryBean { - - private EntityManager entityManager; - - private String queryName; - - /** - * {@inheritDoc} - */ - @Override - public String getObject() throws Exception { - - return this.entityManager.createNamedQuery(this.queryName).unwrap(Query.class).getQueryString(); - } - - /** - * {@inheritDoc} - */ - @Override - public Class getObjectType() { - - return String.class; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSingleton() { - - return false; - } - - /** - * @param entityManager the entityManager to set - */ - @PersistenceContext - public void setEntityManager(EntityManager entityManager) { - - this.entityManager = entityManager; - } - - /** - * @param queryName the queryName to set - */ - public void setQueryName(String queryName) { - - this.queryName = queryName; - } - -} diff --git a/modules/logging/src/main/java/io/oasp/module/logging/common/impl/PerformanceLogFilter.java b/modules/logging/src/main/java/io/oasp/module/logging/common/impl/PerformanceLogFilter.java deleted file mode 100644 index 6987631ab..000000000 --- a/modules/logging/src/main/java/io/oasp/module/logging/common/impl/PerformanceLogFilter.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.oasp.module.logging.common.impl; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.http.HttpStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * Request logging filter that measures the execution time of a request. - * - * @author trippl - * @since 1.5.0 - */ -public class PerformanceLogFilter implements Filter { - - private static final Logger LOG = LoggerFactory.getLogger(PerformanceLogFilter.class); - - /** - * Optional filter to only measure execution time of requests that match the filter. - */ - private String urlFilter; - - /** - * The constructor. - */ - public PerformanceLogFilter() { - - super(); - } - - @Override - public void init(FilterConfig config) throws ServletException { - - this.urlFilter = null; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, - ServletException { - - long startTime; - String path = ((HttpServletRequest) request).getServletPath(); - String url = ((HttpServletRequest) request).getRequestURL().toString(); - - if (this.urlFilter == null || path.matches(this.urlFilter)) { - startTime = System.nanoTime(); - try { - chain.doFilter(request, response); - logPerformance(response, startTime, url, null); - } catch (Throwable error) { - logPerformance(response, startTime, url, error); - } - } else { - chain.doFilter(request, response); - } - } - - /** - * Logs the request URL, execution time and {@link HttpStatus}. In case of an error also logs class name and error - * message. - * - * @param response - the {@link ServletResponse} - * @param startTime - start time of the {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} function - * @param url - requested URL - * @param error - error thrown by the requested servlet, {@code null} if execution did not cause an error - */ - private void logPerformance(ServletResponse response, long startTime, String url, Throwable error) { - - long endTime, duration; - int statusCode = ((HttpServletResponse) response).getStatus(); - endTime = System.nanoTime(); - duration = TimeUnit.MILLISECONDS.convert(endTime - startTime, TimeUnit.NANOSECONDS); - - String errorClass = ""; - String errorMessage = ""; - if (error != null) { - statusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR; - errorClass = error.getClass().getName(); - errorMessage = error.getMessage(); - } - String message = - createMessage(url, Long.toString(duration), Integer.toString(statusCode), errorClass, errorMessage); - LOG.info(message); - } - - /** - * Returns a {@link String} representing the log message, which contains the given arguments separated by ';' - * - * @param args - the arguments for the log message - * @return a {@link String} representing the log message - */ - private String createMessage(String... args) { - - StringBuilder buffer = new StringBuilder(); - for (String s : args) { - if (buffer.length() > 0) { - buffer.append(';'); - } - buffer.append(s); - } - return buffer.toString(); - } - - @Override - public void destroy() { - - // nothing to do... - } - -} diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-console.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appender-console.xml deleted file mode 100644 index 74fa54331..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-console.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - ${logPattern} - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-debug.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-debug.xml deleted file mode 100644 index 6d743a004..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-debug.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - ${logPath}/${debugLogFile}.log - - ${logPath}/${debugLogFile}_${rollingPattern}${rollingSuffix}.log - ${rollingAppenderMaxHistory} - - - - ${logPattern} - - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-info.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-info.xml deleted file mode 100644 index 2b2dd99d6..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-info.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - ${logPath}/${infoLogFile}.log - - INFO - - - ${logPath}/${infoLogFile}_${rollingPattern}${rollingSuffix}.log - ${rollingAppenderMaxHistory} - - - - ${logPattern} - - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-warn.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-warn.xml deleted file mode 100644 index 701c6f214..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appender-file-warn.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - ${logPath}/${errorLogFile}.log - - WARN - - - ${logPath}/${errorLogFile}_${rollingPattern}${rollingSuffix}.log - ${rollingAppenderMaxHistory} - - - - ${logPattern} - - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-all.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-all.xml deleted file mode 100644 index 35c6cca21..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-all.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-default.xml b/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-default.xml deleted file mode 100644 index eb648f040..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/appenders-file-default.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/modules/logging/src/main/resources/io/oasp/logging/logback/application-logging.properties b/modules/logging/src/main/resources/io/oasp/logging/logback/application-logging.properties deleted file mode 100644 index b13d5cef6..000000000 --- a/modules/logging/src/main/resources/io/oasp/logging/logback/application-logging.properties +++ /dev/null @@ -1,8 +0,0 @@ -logPattern=[D: %d{ISO8601}] [P: %-5p] [C: %X{correlationId}] [T: %t] [L: %c] - [M: %m] %n -rollingAppenderMaxHistory=240 -rollingPattern=%d{yyyy-MM-dd_HH} -rollingSuffix=00 -logPath=logs -errorLogFile=error_log_${HOSTNAME}_${appname} -infoLogFile=info_log_${HOSTNAME}_${appname} -debugLogFile=debug_log_${HOSTNAME}_${appname} diff --git a/modules/rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java b/modules/rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java deleted file mode 100644 index 4cffc9aab..000000000 --- a/modules/rest/src/main/java/io/oasp/module/rest/service/impl/json/AbstractJsonDeserializer.java +++ /dev/null @@ -1,127 +0,0 @@ -package io.oasp.module.rest.service.impl.json; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Calendar; -import java.util.Date; - -import net.sf.mmm.util.date.base.Iso8601UtilImpl; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; - -/** - * Helper class to simplify implementation of {@link JsonDeserializer}. - * - * @author agreul, hohwiller - * @param the class to be deserialized - */ -public abstract class AbstractJsonDeserializer extends JsonDeserializer { - - /** - * @param the type to convert the requested value to. - * @param node parent node to deserialize - * @param fieldName the name of the JSON property to get the value from. - * @param type the {@link Class} reflecting the type to convert the requested value to. - * @return requested value converted to the given {@code type}. May not be {@code null}. - * @throws RuntimeException if the requested value is not present or if the conversion failed. - */ - protected V getRequiredValue(JsonNode node, String fieldName, Class type) throws RuntimeException { - - return getValue(node, fieldName, type, true); - } - - /** - * @param the type to convert the requested value to. - * @param node parent node to deserialize - * @param fieldName the name of the JSON property to get the value from. - * @param type the {@link Class} reflecting the type to convert the requested value to. - * @param fallback is the default returned if the requested value is undefined. - * @return requested value converted to the given {@code type} or {@code fallback} if undefined. - * @throws RuntimeException if the conversion failed. - */ - protected V getOptionalValue(JsonNode node, String fieldName, Class type, V fallback) throws RuntimeException { - - V result = getValue(node, fieldName, type, false); - if (result == null) { - result = fallback; - } - return result; - } - - /** - * @param the type to convert the requested value to. - * @param node parent node to deserialize - * @param fieldName the name of the JSON property to get the value from. - * @param type the {@link Class} reflecting the type to convert the requested value to. - * @param required {@code true} if the requested value has to be present, {@code false} otherwise (if optional). - * @return requested value converted to the given {@code type} or {@code null} if undefined and {@code required} is - * {@code true}. - * @throws RuntimeException if {@code required} is {@code true} and the requested value is not present or if the - * conversion failed. - */ - @SuppressWarnings("unchecked") - protected V getValue(JsonNode node, String fieldName, Class type, boolean required) throws RuntimeException { - - V value = null; - JsonNode childNode = node.get(fieldName); - if (childNode != null) { - if (!childNode.isNull()) { - try { - if (type == String.class) { - value = type.cast(childNode.asText()); - } else if (type == BigDecimal.class) { - value = type.cast(new BigDecimal(childNode.asText())); - } else if (type == BigInteger.class) { - value = type.cast(new BigInteger(childNode.asText())); - } else if (type == Date.class) { - value = type.cast(Iso8601UtilImpl.getInstance().parseDate(childNode.asText())); - } else if (type == Calendar.class) { - value = type.cast(Iso8601UtilImpl.getInstance().parseCalendar(childNode.asText())); - } else if (type == Boolean.class) { - // types that may be primitive shall be casted explicitly as Class.cast does not work for primitive types. - value = (V) Boolean.valueOf(childNode.booleanValue()); - } else if (type == Integer.class) { - value = (V) Integer.valueOf(childNode.asText()); - } else if (type == Long.class) { - value = (V) Long.valueOf(childNode.asText()); - } else if (type == Double.class) { - value = (V) Double.valueOf(childNode.asText()); - } else if (type == Float.class) { - value = (V) Float.valueOf(childNode.asText()); - } else if (type == Short.class) { - value = (V) Short.valueOf(childNode.asText()); - } else if (type == Byte.class) { - value = (V) Byte.valueOf(childNode.asText()); - } else { - throw new IllegalArgumentException("Unsupported value type " + type.getName()); - } - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Failed to convert value to type " + type.getName(), e); - } - } - } - if ((value == null) && (required)) { - throw new IllegalStateException( - "Deserialization failed due to missing " + type.getSimpleName() + " field " + fieldName + "!"); - } - return value; - } - - @Override - public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - - JsonNode node = jp.getCodec().readTree(jp); - return deserializeNode(node); - } - - /** - * @param node is the {@link JsonNode} with the value content to be deserialized - * @return the deserialized java object - */ - protected abstract T deserializeNode(JsonNode node); -} diff --git a/pom.xml b/pom.xml index 091662b43..e4f5e41d5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,6 @@ bom modules - templates diff --git a/templates/pom.xml b/templates/pom.xml deleted file mode 100644 index 8c08b5ee1..000000000 --- a/templates/pom.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j - dev-SNAPSHOT - - oasp4j-templates - dev-SNAPSHOT - pom - ${project.artifactId} - Templates (maven archetypes) of the Open Application Standard Platform for Java (OASP4J). - - - server - - - diff --git a/templates/server/build.xml b/templates/server/build.xml deleted file mode 100644 index 05bbf1c88..000000000 --- a/templates/server/build.xml +++ /dev/null @@ -1,185 +0,0 @@ - - Pre-process sources and resources of oasp4j-sample to remove project specific parts. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/templates/server/pom.xml b/templates/server/pom.xml deleted file mode 100644 index 71eb7abdd..000000000 --- a/templates/server/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - 4.0.0 - - io.oasp.java.dev - oasp4j-templates - dev-SNAPSHOT - - io.oasp.java.templates - oasp4j-template-server - ${oasp4j.version} - maven-archetype - ${project.artifactId} - Application template for the server of the Open Application Standard Platform for Java (OASP4J). - - - ${java.version} - ${basedir}/src/main/templates/archetype-resources - ${basedir}/target/archetype - io.oasp.gastronomy.restaurant - io/oasp/gastronomy/restaurant - ../../samples - ${project.build.outputDirectory}/archetype-resources - ${sample.input}/core - ${sample.output}/core - ${sample.core.input}/src/main/java/${sample.package.path} - ${sample.core.output}/src/main/java - ${sample.core.input}/src/main/resources - ${sample.core.output}/src/main/resources - - ${sample.core.input}/src/test/java/${sample.package.path} - ${sample.core.output}/src/test/java - ${sample.core.input}/src/test/resources - ${sample.core.output}/src/test/resources - - ${sample.input}/server - ${sample.output}/server - ${sample.server.input}/src/main/resources - ${sample.server.output}/src/main/resources - ${sample.server.input}/src/main/webapp - ${sample.server.output}/src/main/webapp - - - - - - - ${basedir}/src/main/resources/ - true - - - target/archetype - - - org.apache.maven.archetype - archetype-packaging - 2.2 - - - - - - org.apache.maven.plugins - maven-resources-plugin - - - ^*^ - - false - - - - maven-archetype-plugin - 2.2 - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.7 - - - ant-contrib - ant-contrib - 1.0b3 - - - ant - ant - - - - - org.apache.ant - ant-nodeps - 1.8.1 - - - - - copy-sources - compile - - - - - - - - run - - - - - - - - diff --git a/templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml b/templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml deleted file mode 100644 index 070e9378e..000000000 --- a/templates/server/src/main/resources/META-INF/maven/archetype-metadata.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - oasp4j-template-server - - - - . - - - - - - - __earProjectName__ - - **/*.* - - - - - - - - src/main/java - - - src/main/resources - - - src/test/java - - - src/test/resources - - - - - - - src/main/java - - - src/main/resources - - - src/test/java - - - src/test/resources - - - src/main/webapp - - **/*.jsp - - - - src/main/webapp - - **/*.xml - - - - - - build.xml - - - - - - diff --git a/templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml b/templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml deleted file mode 100644 index 72251b47a..000000000 --- a/templates/server/src/main/resources/archetype-resources/__earProjectName__/pom.xml +++ /dev/null @@ -1,24 +0,0 @@ - - 4.0.0 - - ${groupId} - ${artifactId} - ${version} - - - ${groupId} - ${earProjectName} - ${earProjectName} - Enterprise application packaging. - ear - - - - ${groupId} - ${artifactId}-server - ${project.version} - war - - - \ No newline at end of file diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java b/templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java deleted file mode 100644 index 47a2d58dd..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/java/general/logic/impl/UsermanagementDummyImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package ${package}.general.logic.impl; - -import ${package}.general.common.api.UserProfile; -import ${package}.general.common.api.Usermanagement; -import ${package}.general.common.api.datatype.Role; -import ${package}.general.common.api.to.UserDetailsClientTo; -import ${package}.general.common.base.AbstractBeanMapperSupport; - -import javax.inject.Named; - -import org.springframework.stereotype.Component; - -/** - * Implementation of {@link Usermanagement}. - */ -@Named -@Component -public class UsermanagementDummyImpl extends AbstractBeanMapperSupport implements Usermanagement { - - @Override - public UserProfile findUserProfileByLogin(String login) { - // this is only a dummy - please replace with a real implementation - UserDetailsClientTo profile = new UserDetailsClientTo(); - profile.setName(login); - profile.setFirstName("Peter"); - profile.setLastName(login); - profile.setRole(Role.CHIEF); - return profile; - } - -} diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml deleted file mode 100644 index ee83c8c66..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/config/app/dataaccess/NamedQueries.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql deleted file mode 100644 index e00a65ad4..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0002__R001_Master_data.sql +++ /dev/null @@ -1,47 +0,0 @@ -INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (101, 1, 1, 2); -INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (102, 1, 2, 0); -INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (103, 1, 3, 0); -INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (104, 1, 4, 0); -INSERT INTO RESTAURANTTABLE (id, modificationCounter, number, state) VALUES (105, 1, 5, 0); - -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (1, 1, 'Meal', 'Schnitzel'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (2, 1, 'Meal', 'Goulasch'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (3, 1, 'Meal', 'Pfifferlinge'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (4, 1, 'Meal', 'Salat'); - -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (5, 1, 'SideDish', 'Pommes'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (6, 1, 'SideDish', 'Reis'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (7, 1, 'SideDish', 'Brot'); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description) VALUES (8, 1, 'SideDish', 'Knödel'); - -INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (9, 1, 'Drink', 'Wasser', false); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (10, 1, 'Drink', 'Cola', false); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (11, 1, 'Drink', 'Bier', false); -INSERT INTO PRODUCT (id, modificationCounter, dtype, description, alcoholic) VALUES (12, 1, 'Drink', 'Wein / Apfelwein', false); - -INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (1, 1, 'Schnitzel-Menü', 'Description of Schnitzel-Menü', 0, 1, 5, 10, 6.99); -INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (2, 1, 'Goulasch-Menü', 'Description of Goulasch-Menü', 0, 2, 6, 11, 7.99); -INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (3, 1, 'Pfifferlinge-Menü', 'Description of Pfifferlinge-Menü', 0, 3, 8, 12, 8.99); -INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (4, 1, 'Salat-Menü', 'Description of Salat-Menü', 0, 4, 7, 9, 5.99); -INSERT INTO OFFER (id, modificationCounter, name, description, state, meal_id, sidedish_id, drink_id, price) VALUES (5, 1, 'Cola', 'Description of Salat-Menü', 0, null, null, 10, 1.20); - -INSERT INTO RESTAURANTORDER (id, modificationCounter, table_id, state) VALUES (1, 1, 101, 1); - -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (1, 1, 1, 'Schnitzel-Menü', 'mit Ketschup', 2, 2, 1, 6.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (2, 1, 2, 'Goulasch-Menü', '', 2, 2, 1, 7.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (3, 1, 3, 'Pfifferlinge-Menü','', 2, 2, 1, 8.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (4, 1, 4, 'Salat-Menü', '', 2, 2, 1, 5.99); -INSERT INTO ORDERPOSITION (id, modificationCounter, offer_id, offername, comment, state, drinkState, order_id, price) VALUES (5, 1, 5, 'Cola', '', 2, 2, 1, 5.99); - -INSERT INTO BILL (id, modificationCounter, payed, total, tip) VALUES (1, 1, true, 14.98, 1.3); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,1); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (1,2); - -INSERT INTO BILL (id, modificationCounter, payed, total,tip) VALUES (2, 1, true, 14.98, 1.4); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,3); -INSERT INTO BILL_ORDERPOSITION (bill_id, orderpositions_id) VALUES (2,4); - -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (0, 'chief', 3, 'Charly', 'Chief', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (1, 'cook', 0, 'Carl', 'Cook', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (2, 'waiter', 1, 'Willy', 'Waiter', 0); -INSERT INTO STAFFMEMBER (id, login, role, firstname, lastname, modificationCounter) VALUES (3, 'barkeeper', 2, 'Bianca', 'Barkeeper', 0); diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql deleted file mode 100644 index a070e18a1..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0003__R001_Add_blob_table_and_data.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO BINARYOBJECT(ID, MODIFICATIONCOUNTER, SIZE, DATA, MIMETYPE) VALUES (10, 0, 72861 ,'89504e470d0a1a0a0000000d49484452000000c8000000c81006000000fdc872dd0000800049444154789cec5d077c5545d69ffb92d04297d8404db020c15e028a9817052c5850888b65dd447445d85d753fb16b6eec8a5d41455c13171509764511352f7614ac80080a449a0816a4a4e77e73dffccfbc37e7bec90b5d77f7ee6f3d9c977bcf3d77e6cc9c32e7cca48aff5d9b731d618174f552c00114f9cda4db8bc16d754d6ee67d7314f0ca4c9cff3d00e76e2a63ffbbb6e945726a9343926b7e5fb2eb8ccde26ae32f2e7fc92ec8b3677b8eff5eb6a98cfda75cff5320cdbbc280ae024e1ef0df003b00ee88bf17b3e7803b4e92f7d0c0a48976de46f2b9b9d7b30a786e92fba6e0be29e6cf5e2efe41fcaf06fc1a10dfef95031fc9eeffdfb56d2f57012daf7451bf91bc925c5700477f3ad4afc39a7e8d83f78803369ec5cdba52009b29d7de7e0a3ac9e49afecec6b357847f2479cfffaeffd42b0c185180267c0d31d042c04310cc140ca054086cea4d0aa6a501deac608b1680b798b0654bc083016f05fc50c156adb60e24fafa7dc7317e5a327ecfc6f7bc0f38c0fc5efafe941b01430a866e50902620872bd4086058fcefda1a571830a280966718425aae8f5190fa8dfa3120d7e8779283160301494e3e5050cb11c9d5ef55ae312e699cd2b8b5c935c97340aea93d49ae5dc0b0f80fbdfedb3d9030a0ab80f62c4820e83e36e139c702920091e52205eec4d20b96b56923c49ec507cedae502299cff6a35a0ad540ca9d35aeedaee2d298453437f4e4f9737f7747af802e81ded558b1931961c57fecfe76b77d128241daf44acf7ffeefc2caec02d51e8fcec98f815c0afc07da728dc29717e32bef97871a46f29354ca83b61fd7542d416d7fcb6f63221aa2f5c377eddde427cfedadb137eb84b88f7d6bcd0a3bab77ac4c38012cf032708cbcc7b0f1003cef300df357141f7870129a451c1a063d2d70ae67f57f3aeb0020e6f573ed145f03b148743f046f3795fae8767de7a48468610ed4eeadca5f34572926ddde2fc761ba45ca7a535b693cf39f3424b5bc909dba9768ac4c742349ed47843546ed738a3a3445a8a1ba372bd9b926bb1935807b96f9e3c0bc8b31e07cee5d1fffea4f0c6eac6f7ebea84a8ffb276e9ba57a45c2fa89ebd6e9d10bfcdfbf9e835ff924ec8b47bc6af947cff72daca168d6f290a24d75a6e49de489e09f6078422d1f24d3064b62f89bb9e40e8776a6f1790f03fec952ca4f29f7665039242a009cc054e03260218e781b4bfa24b17e71d212e587ddbb85e6542b46dd3b9e4d46952213c99b2c721df4a6ba45de8f283baca7bf70a3dd8ed1ce10fca637c0523d54104ef54c336ac70e9d62b3c0ff85c312a8af7528101f96b187f575c8515ee54e86941e111e079b83fac70799f8bbb8a814780e7a9f703cf1379461b79725c1c2dc11d8d5d974c9403b35363ff05e3e5803cacbacb872f09b17cf477e35fbe5d8847ca479ffacd3772c05e52bbccbb5e3dda08179e42548dd79b38b9f88d6f037f1010fdc207a61e6080ff5328962bac80291971bf931cbb0c9713ffa90ffcada1cd1d52ec86f46dd7f74839cfaf6bd3ed4cd9dfa195a18b7bf490f08ed08bfb3c296fbed2f9a5c3bdd17714c7539352a4702e7f2ef062c24d794b302e5c3c077a5c7e03f21dc1572a7a118b3cd3f59e1853552565af5bc3830b779306d47d0d5fce7f5488758dbffee5f97f08f1e592770ade950ae3c5cc07effdf967f5889647926bc8ad96732ecf24e7d7b3e7c38024bfae79ff1f57a1fcb72890b0027a8061f1cf41ac375e6174fba5c7d490b49ccf9973dd5b474b0bbde5fa36a9674b8590727ecab24172a089279d3332e6c64dd0d910f0af930834298e0a61d87ff2bfa448e6021f053cb1e220dc351587c68bf1b5f9186853028ac4059fc5e0d3051d1e096ff2f2def5fef2a3b4e86a8baac3af1f21c4ea51cb9e9afc8c100f3ef08fbf7c78bc1035876c98d0d04fddab0718065603299ca1803fe0ef3400b985470ac535effbe30ebc2d746111376008f1d0ab84e7ae2aceedd041883dceec396cc810e9391cd562c8b07952417c18fab4ef1bf2a6a39c375adc6a18244a1e36da7031479be32491b78d378c22b82b0fb8499f29ae665fbee124e5b2e1a086215f49b9ac9eb86eda0bd2d39efbf6870ba64c11e2e9cadbce5abab7ba953c98c646402886c6a31524b9df648512de28ceb7e3f59fae40220ae8d014b227686085fe2ec45f6a6e0c771c2c3deb8f7a9c34525ac2a97f4d7bfcfce1f29e5d9cfebb2d147605908d097f0ad4d128780e6e12cfc1a600ca809fc13c94e2c080c157255554a3807f0d3c8caf570331b987b34957e3418d177d5f2ac4fa9fd69cf2c47942bc7ec0e315fffa8b101ff678e9a33558e3696800dc17cf9c0e9c069acdb223c807de7fcbe26518d055c01907488610290c2909a3cb4a2e3df06221da7cd5eefacb5e91b2fe51ca8cc1f7c83f5ee3bcde6a4693868c033c0cbc690fd8c5046ef3b08b418f8d8b0413bda2175030f04c2a347d07385a63ebcab39c4322bea2a89f5a7bd4fba942ac1ab674b7717244dd79eef997bd592f656f60e3cb0d4ca1d41f059c0ca5a34dc83d1aae58fe381e77687b33b085afb0027cd19bf4a4bfe670f6e1d7f56ebf548ea369cf7c75538a1099a7f55af7dd04e96134a6762ff645746771acaf38bcb0a7a81509356d45142e3b55e1655ed47e96ff2dc3dfa3dd2def8a44f172747f44e15e2ec3c3c0cb81e78b223ca7dee32a5c3e17c6730af78097030f6bbe8a0c3e87629a21be72357de253e1459aaf22834f21c81edaa82bf479e8a1dda5c268b7a4d309d74a4531f4c54bbb7e768a103764bc10bee66a21fafe6df01d3b22aba7e58b0aa66111360db1e894774d18a2c5784c0521f295220ae829e23f35add25540875809fe4941bf5d464f2e2dcdb95c88ebcf9cf2f68b2f08913ebb43c3cc41f29e502832cc4ff2a815aff98a2320c7246f618d73f950d35b4cfe144ef2e7327a11462fc2e811fd987c937f69c833d10ff01b93e748b3f8cdd5fc6e923cfb8ac897bfd43b5aa4f6930a629743baaf78ba8710b7674f7bf46de9698c4effd7d7a79e2adbf9aa50eb5658b40f2ccad3623cc937d65242b496fa0e2019ba11e0866afd3d5e29db9b812d74b90a38a50ccf5230243be8f2034abf3be61821323eef5659faaafc2d2b74f219afc93f9e25766b3922cea2c914a6055608fda32d1ae0b94ed4c2971e880a20643825782e338ae7295c3e95a99e032e804780e70177912c59a83c1a892beeb3c88557b87c2a8ce7b2705f18f765197c4e15e90a075f64c1656a3e155ea8f9cc637c9a1e0ed1dfc8cb0939bd5b494fa345bf56e123a402d9f7829cefcf7c5888bd871dd2ed2b69817d32e1f52f9677c5bde729187a023838d1592d05c023c02bd9cb5e05244552b2291cff8eae88024e21c3e5771714dcf846875a214e9a72d1f0b1b365fbd6b5aabfbfb3fcdbbad0ebfb3c1dbd2d4fca52bc45afa8c42c7a856792e50fb9ce0bc8877a2bc94725f04cbd96a1e86731fa25c00b40af447b382506bde41eb5c96f4c9e33151f49f8ad60fc4634bf345d6fd2159a93b27aa72ba4a1744ca7f5833b0a71ccddc3e6f6a91662e6fd6fe4bdb45688ea97d77f010e63f28c7ea47989feee3039760ad8cbe8ef2e60647338df92d71f5d814414e0032c24f11da675ede47b1c173ff2f0928b074b2be08456a32748d7d2e928fe6ff7cb842f8833a3cf6eac2b4c782926d47c087819043c4f2f062a3c4baf4144713900159e093c160250cf459c3151bc10d3656c00293c532f5e2abc50d32f009f0acf56d92ff22b2fc7f7d173cde3b3c49c789c32e0bd366fe039739dddda48cbb8d3693bfd69b0f4040fab1d78defa3942bc77d0f3fd67af97377c2c9ed116363c0fddbf61e018507aea590c380ab084c1c50cfedeaf8802da838e33844666dc5bbb4b8d103bdd97b5f76bf2efa191a15927f83ded4849f27b46cb99368894a14172ed3043a3848552638ac48de25a3eb421a30cac126d6099f42a809362aa04bd4c162a73f8b8b018709c5f32e0285416534c8c5f2ecfa6e1a5e955f2e97bd3ae94dcd4637797be50dff5831f3bbe95103b7f9ab9fc0be9617f59f5ce0d3f7f2af0c980590c87bc9342d10a02bf7b7fc17d6c9edbfe06d21f2d84155620517dc60e27ef7a89ef1a5ef1d8c49b2f9396e8888abbf3abe4d499724beadb779e246fbac2dba7e521712e385c5dc2c9d5952eb4f1bbf5be6c06c3faef70d1f573b98c4eae41c705de53d309b3f787d9fbc38ccf30a3aff0fc24df97cb20bdcf765fbeca95dadc10175dcefdcefc96b709d165c7aeab6e7c4f88bb9e29fff3a27385b83a34b174947c93b3a7f36afa27eade361f2bd8fa76055ba2ce200da18254d425a4a0f092425d8101ea6e0ec75bf17215e072ed7fc788fbef7978974764bbbc30e9dee9470ad1f9c25d5f583a51fe7181d3eb9056861c303913a69c858173b9e6fd6c9563848838bddc24e3c43ebe368d5f3bff4d8fbb00bf0cdfd41017bb52d3d21ecc96f27bf0b5c7be37ed2a21ee5835fd377fede4ac4bafbee4f057d43de92a36a0e5bad5f10a527d4a1ae45b87bc28bd9a0c0a2627342f6efbeb8fe2818415d01341448190b43d8e4a39addc8f399ed6f9921f1f9d2f3fa943eac4ffbb2cfae7f342c3e35cd60258f8e3d00d8360afc203901e45a67a9776b9159ec742539570c15d71a2a2a7435cf9e0d1e8d69845c72c38edf910ae426222839e33435c01d7ddc6a70bbc58d5b54b5c2df2f31017b71423c00b359f59069fd92a24e6ccdcb2212e7df51367a7ec2907d5c0f61d730b8438b2f4d495bb5c29c4274fbdfef67b7200d6fd5253438b8f3a04e0022a0e847707f0b180e094f2ef7588b3c07c6ebb5d78bfe6ab44015faeff71cfc3693d2609d16179467ab954acce0fcee107f96b46310f7843f4e67c27fab53a6444728610a8bc2f0ceaa62762f5b059c888cbb14d3e329907efe8f45d176f2f34e8337e93876c897e9210977ddc317e81f390dc9692675ca12f535674bc54885dd6779f709a84596fedf7ca37c3849875f3f44796eca5eed11e495e621a7c319df2ceb45c43b1e89e5ebc25386fcef57b5720a80f50c12661288ed39ebbf895f4b652d31fd3bfdbe4d6f2b70ea1be43fd18b86dad8026e8b0521c7a82aeb4645971973b8fc5564b31e0b2a13866824b5b6880b2aef400c18020d73d177caeb684b8f800d4316c169a2ad4aebc7aae1821311ee2c2341a17232f60f44dbc140561f92a241608716da1d8325d2d3f69dd61bf9385e833e1a4437b7e24c4d7bd679c551e1162dda45f9e6df8b3ba470f38c569ac9e84f6682a31a107c84362db3cb4e5323e4a14f0e5fad2d327bc947385b4521f68b7ea8db3e48f473b3bef72b508aea5e5a2ff660a55c6aa0d01c859a596b3e8dba49c15a8fbb4bc642a26f85a1d8d8766cbb1a25702fab15092a25fcce8050c17d02b64e322a6984c7ef39284e42a412fb399fc16b0905c1e70572bae4ab1052ea79d33d0af70ef727ad76306ad1262dff29c65cba5c73163c2ab777efb286e2295b5185071a04358f4bb561c61866f7345f27b5720aaeb759ebbefb2f51f77eeedad4608b1ffcbfd4e7db1a3ff5be8bd81fea2a17d714de13958a476510f5d29da466120b64a038759302e048b2cba7c65014a8f661470d0c180cc648be585164f42683cead1480f643ff01dc673598c4f12b330eecb32f80c93258745fe584cb8047f570ab0447b380a77816769854a7c293c171ecd4c78343cb6be9562cb69b35aeeb0e7b1421cb25fffcbf6972a7ad67dd3fff646ad1035376fa8e079f35e4fe087038f002f31e1761b706410d15e4ae0c3571c97ecf6e88043d709d1eaa3f475d3fbca1fab9db69d3a095feec860898057c255126f3e0ca29842cf54f7b1fe136cb1991b44b1fa8a02e08a5e72392683cba45fa80db002f57ae6f1307ee3e42fb3297e35bda007a5e871c32819bf31c55a01fa61f06fd2afd49e378dbf4dbbfa8973fcecab8e13339e1d203deb1ee71cbe6ed92d5291944f5dbe00c9247c2d84d27ff9da87a738b57b245bfdfabd2a90b0023a0b474e1cfb1edafbdad41be53c76ceb09d9e901de0fc14aa3ce96f22e83904f3da155e06415985e18bd08ef624b82b6fb7e894a04d45b7e5a28069a61660d322b765bf04b355c6814f2a2474f11d8a6f872d9697989e439ca7021c218e6215e210b49858c13c9cd8402b34db8185e22a40cf926da62dce2c66d1966c999040daf72d4ede437272e84e037aef2e3d9077339f7bcc27ecbdd158aff3ea115bf6bae0a102e02ef00860097e07becd1409d56d60b1df571ca3fefce02b7b2f971e47dbf69f4cf73d8dd9cec79d4e8ff3282bd9623059e6b92ca4c843300ef3ac2bf5c4e9aafb40dfd1868732902a028686a2c72bc8b35808a9c44cce207e831e8e85dfc266f2cb43ca4e52c388f31b01bf0a2f481c0a0ef0bba543b65231fba1ab8e6376bc3b4f52ec76fc3e977ebdb3109fcd7beb8325efe29eb002dee326d4f24b38c1c59ab671dfd65b6cffbd2990b0023a0b679582a1ef653fef78f3fa3183e4bfbd50bff3a422117031a547607a0e3aeb435be80a1f8461ebaab45ba778e3d26c039e43bef268e4b49f0b5c790e2c7416c767624f2253e36afacb09585ec4679ec1676c002abcd0f41c4891c8e7f603fd30be2fa1e7104b070e588a0a2f08649b450c3e93a74f46f0f6cd1a782d17b45edf437aa087b43bf6afad3e948ae4e5e71efd4405e9627b735d04e89abfeb104026231a062c002cd91c0e135ca0ef4c0594beef79336fbdc9df5baad3e89d2e8ff80af06ef17ad737a3f2a3dac7b69641064c2926eafcc45973564320e0b1b290514c91287ac90d0d538e89bec3c69f13480736e83797dfb82c3193dec61a46997cbe08648935c9ef160bd91e2d3d923da55df641d773fa4b8fa4edba0e377c749b105fd7ccb861f549ea16ed81907cbbc00b184e8a2413300258c2e016bb7e6f0aa444010a7e84e440bbe41f8fb61a72bd64759fb49bfd6caae8c4e78b5465920a59be15020dc4626ed1359dbe1ab7c80e41043e1591ec5c65bf4a2f4929289e665b6949b3e5ae760ed26e2348bbddc834dbc000c947086baa9e284ad47396e48042aba5081c21c01c786e1116e2d3138f9e8e1ddc17c67d0ebe07f8e685b8dad4b49f7ec8fdd2723b719f31f3a649cbedf5b71eada401471e090d382a557381534cb988118d009630b899974e3b960651b7a77bec9422278a9cc8a04e9356c81f478bb2c3e78a449eafe2b632b0369519c57361c0d8428a3c64c4d70688be635bfb4abc961833882c86464c3131fa01f9d8347e631e2fc68596bf84fc26358c821e8e8bfb0a9be4770b876c9dfd9d65fe1ac9ae1bf67ce3882b855878d897535e953eff2f7356de545d8d9b10b2f588a3087092ef45c04b80937c9702d2738b3787d3f8ebf7a2405c05e20b6d865f7d5bddce774bd7fe938e4fbdee87ac16887e7e419ad5c58c854c144e9e0362ab729a3f11ef52825c8a8167cbce2041a9b4780ed9ba9010d95316cf2116c3263ef3189f0a2fc3692083f404adde53c806888d4f3e00a712df1b991c602bec2a80c22b43b2c0c62eaab2ba15f9dc68d0d9b463861c650b7629df7555df3a217ed87571e3cbd2725bb9b872ce06b5ba151b5805c049a1ec81df6940d2df29df3e0f7fa7cd37576d128746e19f7ff99ef4f9d78c993c7aacfcf7e9a13347dc16e74904e5577141f25bca4230a5f8aa0cd433e9898dd1b37bd6444fd18f6d1552095cd1b31b44267dbe56e268f9a9041e06fd0ab48949df05fd2c6d6025e437e6f1327a317e2b8cf6284cc22f85fa2c1e9495df606859d1ab741cb1195768ef942eed2f16a2e7b23ec7ecd1284568ce336ba6d7abbfe92d7b4a80ff85c14cfc7d3120c97744c12dbf36b2bd154858019dc61851c0df3a205c3dec9f974b8d1aaa09650cf0b7baa0892e3621bba0014bc1e262566a4f42ad3114e318a3b0ca4ed2169760829167f11c08d769948a9e54001be29fb3c7b0399f68854158944f163a13cd5c83c8469af14c240bc442020ee887f19cc263969c83b784711f2c47840073b445a8ded3dc4555168a93efeb055c29cc4db4e09ccc502bff1c889dbfc93ca4aab710ef2f7ef1894fcfc41f6960e55a6026eee303d3054e27ed453692a93078c380f50da2bf5e7cf79cdda527ddfac1f405cf4bc3487cef94f869e601c5cd437e956cad81d6d0682784d57a622b51cf594330067dab67ad4359da63b51944d42a26bf2cbd564a8fcbe867a2554c7ef98e08b6f4dae09a5f26e337339e5fc7257963ed51a2e91780be1b4f3f29bfb68a7a9a1f36d32369d9adf569ddf714e283da97de2a95946a1757fdd688ec43ed41bbc01799bf6b1c7f0fc82fbe68f33d91ed5d488845456a087f517178e11d859997cb0eb83b943ab23a5a2814cdadf18abc0c752ff09e48d61c0bdc53b8bc4fe161e03d919b33dceb13c5fb20d973ac17567f47415111f0b0898bb1820afd143e12f840a22bfae07dc467b681f7d4ef233eb34d3e9502f22e1543f15cf43bbda198d6c602efa9f7fac9c073268ebdb4e4fb543b4d10c38def9f8cf7802f79b7c2f3894f4458476abea8104be1d9f88e22c6674f85c7f13994f1893dc3c0d758e07dc047ac7d894f1e586ad695f1efdd479fb58310877bc737ec8182c3560b0171c0508b73144cfb55413f29c3bf42df281838dfe53110cf6e2613741fc9356dde29e5baed9c8e7fbdee0ef99dc778f9a9efc7b707f65443bfc5c92fe480da09f2ec01773dd5bf28f0f3747b9bf4347dcfa42f9f37c707d1efc9e42e6cd297eadea43f99f15b64d2a382bdb8f1c6e538b17c107dd61eba00d065f4c65ac685cbe88d34e557ca5b2ef07093fc4e66ed61e33726cf54b0b849f24cd725d5e32aaf951e8833cc59d11a5bf5b47e59413a80ae05b2b7b85ca71cab6008597f0ef6a0d3f2b9d9d7f6f2405c05f46ea2ca691429ef48c36acc9f163d2b159bf3b2f3dbbefe80a6900c59fcb00bb5c59fa32dd90db88fecc60db84fe1678a5fa2f8550e85aea27469fb0b692d66e277013a0acf005e067c10a8ff13ffaa95ff13069fe98ccf74c667bac127e1d761bac9c722ff6850c991fff371daa6a358e1c4a7b4c072189f0aefa70eda9578187c636f2cbc370b7886e6330bf7115f59b84fe1282414fbd19bc05719f0189f198ccf0c7c4f0eee53f834b45f2f1520927406e1fd8bf15c41f4f766a64f86e6868e6bb59310ddafdfffcebd3e95defbc2499fbc7110fe488b8b74fe088ed2d5a12caa1ba1b4609c0def41f1e8b62e698a0311db5e1d9bc784ae10e2c26fee796d5f3905b65cda7aef470ef16939e3fc73389ca9d46f2804a47eabd4f54a9003edf9a9509f8bfe58a5e439ee585ab437e88da1f6d65978aa7f4ab52429fa65267d87f611cb31e54cca2bc95986c1ef203cc1e967805f0a076620c443f40b997c4cb5d02f34db234e0a329be2578f0bc1f9857c825f3d5ac3144283fc717e07b1f6b0f19ba343d2617ce7623ca7e86d645662eb5e6d2bfd7359ba8dd8a76ea91cd19f3df0d6238b60207998e93c54b87b3f02c213a1dd80057674f090deae0b6d0b0023cde124d1b59d14885eee2e51c08f0d8f68bcefec7ef283d3c6b6ec71bddf00d95428d574819e70292bc51ab3a41829290e35614530b02a2d69b622c9e25a2c0f5f85b0a6b2823d96661b17322860ef53782e14de4cf065cd26e17c5a43534ac1165a425cd64d1dcd7c7c6fbc77ac7fd25b6d7df5aa5f779122735ada9036a31384b874cc197cc4d68c1cbccde433072118969e2978b6d946a64fb6d8bb55763769b1b5c86ffdf9c7270831ffa5992b7fa42c2d3a10687740da5e1b8a446fabbd8709b5d110065ccc5e8adf75c80a7ff743b1fdcecfef30460e6ca7ceb9d8af2497d20c4388cb970e2166a9ef27f9e56b72907f92a7e2666e92e830fa9516fae84f6b882b58f1eee03e937e89a60ff9481ce2b28f374b7b8441cf16e27218fd60c5bbfabe2c8e379dbedc5c7e25be58e19610d726662576d8a3cbfb590572ae7fe999752fbe2465736de3127d901b9d4b028fbb118650e3b90a9afb1dcbdf6150e942d64dbeb6b5027115a0652682fe59cc7d1f3e7d8f47ae94c8df9ce3bb0f8fb3649215e8553673ad2007b6046ded51890aded8449765e0c9d2295d780ee3b48554c8f8cc637ce6313ef30c3e4991f042c264e9c0b64ae16226e0c9765565f9f8cb977c37f35d39018e9f76f9f83ba50bfcdae0c786bf2227c2da11d5dfcf961371e617bd2a0e90967ecadc947fb43a41d8d78c2c15efda831c048bb9b99b3a264f9f8cd62677b96bd7e37638540eb85f9e297d13e73378ff5290ce19a181a4cf6bd8ddbc4f57b6e7c67f89087a22c0f562b984e7e5dfbe47a684ad32d3873df2bafcdb27ce14ac7960cdc75291cd176fb5a2c677c310908a830a6351cfd4b45c2438f0c955efb5243bd8924738bf9516fab4d8ece8f180fec3df5141ee7dea0da9f70b275778cf44dbff48a7b79fd66a6d8f40d624537cc9f8658bef0179b3ad51062ade2df429bd3db6f6c2f865f2eceafe85f424be5217a6eddae9342176fc7eb7cf174945f0c5b28af98b17abbfe903da48aee95c1dac859082d16b7f8b18f102c048531c24bab6b10249e4790c5f3226fd40e99ab538a4f5c5b71f0f01f4bb86b6f6d8dc023d1a1865505fab90764b27fff102bd98001518efe3e994a5420599b2e1d190e760e33360d16945a504bf0016799916a812f099a9de9f24cd962d6a3b6c7b7841969b9e4098e78001f853edf27f7f76b7100fdc3f6a8f871e16a2aa68ed71d5c3d4030d3f08f1fda3732b7ff4cf6aefe2a52f385b883d8f3d78515e963160884fa59878b619f13988da178a5c0fec24167833d3275b6e685de1171cae3ff9b7b96fcb81f3fd075fafff15e78fd8065c23290e0a0150653b425ab6cd18290924def3387a7efe946bbbc9df760cbd78a4bf5545cca3863f1450ac99eabb9821c417c72b7532897abe9879e836f97518fd4a6bb24325e82b7ac1745d93df589698491f8befbffe75d59b73ba08b1d0fbbc6e9a94a70fc6bc745a991c3191479e29f6e1d457c6ffe519d9ce150b262ff18f969d77e327d3a73d22f5c9a3df1ef1ee5eb2af4e6d9cb7441a982d8e6b55eb9f0fd332adcd313b0d13f6ac2b7bc5bb6a0fb6f81e935b3d2e98bc252d1730da63a3b32737b2e2bdfdf22e37ed2447f6dbdf3e5df71ad27bc9d3d0903c11e6a19047ad3d6f78269b9e9db5ad1488ab802e1044d3443d8f6ea77d769914b0d017a1257d8e1031019c89b4dbf06616e85187c60a0915ac4c1a322901a6048c7b0ef9caa371c66182b61412dad381599e3bf19db38969b6bcf2b6580f1835c16469cbcb059f05a01fc5ebcea969f5ebc542947e77fd2f77fe24c4bad77fb9b5ea35f5223a71adee1a05eba70bb1b870ce052b6f97e4669f5179c233b2ff86a53ceb9fab62b7e4b8e5851060a13e39d1453b1434c56720dd9314ea547542a4549b3be2bdd137b77fa5f3e55539427cb8fce57b67dd8defc191a30dbb29a8435a8d26f44600a7ac977062a83d6aa9480ebea3fff8162be4eb67ecdf6ac2b5f2c74b4446dbb651c5617aaa95a6a72a5c9d9e4bf216c1f7e7c57fbf80a72615c738e06a0dab34a9fc2a7af61d1b5ce0eaabec068b29776c2fb9eac675bb2ebf40888fb35e2ffa979cd0260dbea572f22742cc7de1c3590ba442fde1c64537fed44ecad79c5fe76cf017851bc4f4fa057e238b37ebbacadf1ffbe57d7f7bffe56bbe1bff93f47c67bff8de937e9dcf8737bff48c5f70997e4687d3174ac5dfa5a1eb375972fe487d256d40fbf64204f6e0ca4a5a70abf8d705b7d6745d458f57d4575ada23a6a82a403f0cfa8a9e6dcfb0ace6856cd3f66c79d68e52d2d7ecba7afadbb21d967e3e7fed9a2fd4df1ab96144f2bc7b62a843b111c030fb3de9b5adb3b05c05fc0197fde491e3fc13bb4237a4f43e7398089ea8d7939da8c74e34132e3b412f76629ac26327f65156959ae85d64a5509655849dfc579eec6434d02f4336d550289088de369af83470bd6db4ed64b76c64af94e33d31bec3463b683e3d337b449ff406bc48f1a5b7b7e6ed1bcb568972feeef8673b3f2c2dc41f462f7af89703a37f11feda877fd51e09788a823535d2f618975a59eba70f3ce2ecec677b48be5cc6a7cbf874f13ee293b27458fb5af8a476099ed4188df87a433d9cb06e5e3bb6dcfda601ef4b393b3ca5550b9c7c48d02fdcf2afd45440ca5ea16c2c828e4953af7590e516062ea78c3ea9a7f41ff87e344cb072a79de2daa327b50ff8f5c03fc91765156979a6ef2779c6f32e9767d0a3f6487ab29f0e6418f4253d17bf96030f1bfc5ac687f741e3098d52217fbdef87d74cea21c43d2dffbae09aa38478ebfc7faffc049ba0d64d57b0f62a056b8e50b01ab0ea4ac02a05375c01b821085f39e1e1fc0ad92f631a0a8e1c31497a36f3bfac79ec3bc9c780c69b7d3ebc64edc1e42d0e57e3c463f21666f42cfdc7db3be9b88bc933e7b7dca0173c3621bacad3e79293fe791c9d8048c71ba499509fec896c2c92eb106d0f4f72ed32d8ec6b1b7920daf38828e8bbf8837b5fd2e318f941a98569e32fbc4d04d720289b293f693e7a099e53b8ad10ab582f66533d48f30a0979c8843c876c58105370767386c573e079f396453a67aea2db785fa3e74fcc553bac9bbde40969695cfee3a039d252fb6ddd4fcb16f41562fde85f572f9296c6bab5bf5ee9c3aa9cb5af2cd9533eb8d4bbd08f25a7b44bfbb6cd6449ef84d08ea917f8efc31a8325c4b764e9bc6b5e3d4c88672bee396cda1baa7feabb2958d71710bb85d67604bc5a88d36fbac4c9919662d7017b753f4e0ee4384bcec5fb14ce0baf62bb052b0fb3d8b2a9a50e11008f2daa3ab8cfc4f99a19da37e5c4d453da4a8b37343de5e799d2a25df0dba75faf6cad5ea03d10e4d737c0b56fa0b512a44b36926a5a0c1811c6458587fec03c62d4a91baef50f2e7bdc396bfffde3da23e651b755fcd93cea2415deb1c5f3d1b86f83d11ec92aa66d3b3654b2f6b6edc185f1d1b053dd90f5526e2aae2913f7490bf88d6e8f77fea0859cf84a1abfa8c39a13c951edae800b14240552b30b7e27c57235f04780cf57b0ee6cfc0e58ffad7cffabf5f7fa86cde7bfbd3d66f63a21dafcadc379f3a4c7bccbfdddff7984348442a9ce9d2d2e4cd01e6c735289a9ef250fadb97b8655b2f9c2d5f4d5df5ded4134e9513abca25eb0d07226e1a647d2eaa3f4fb3aaf918afafd2797bd78a97a904257b45b3585640936c03321b9d79b912e0674c5465e5b5b81b80a6805028bcd5ffbe8b3eee409e74bcb2f549752dcd79fa8f81a44aea013f594fdc13b3469819e5ebb50f7bb586328463a60330bf4f4a2652973614b112ac95779dfce6a4c84997c20269ef8ea47d435ac9382ffe382ca3bfdf32ede2d7eeeb5c7e54435e5e33b4794e408f1c1292f9cf5e63942ccfc7ada981972c2fbf4cbe90fcfdc4f8859def4b299ab25ac7a63d1277f937faf78fdc78fef90f72f7af196e913249d82673f7abe83106b1ffbf9838fbe14a2ddfb9dbeabdd5b88d617b7fd79a7a9b2cba7a78c6e257d9d0df7af1db0500adca30f5d7ecedda74a7eaa6ae7d76260d761a06bcbb13606bb7dd7e328df823ff1ace157ddb28fecbf6b52f66cbbbf0886f892145ec56d2d8173549a9e38addbe1d3c4165b338ba01f9462c6c04b393275e755720a9f31e3d5c8e734e0e0f2375c0788ba8f86ef000fc57de4f253a156045f580a28f1d4f92dc685ce132267c089d3eef7d75a5e74be687b725c482a1ffc4ea5ad4758ecdeb6e54d3069840ca332f0906fb4472c0463d2e715d3961d1bf45a9f650f2eefee86e36a5e17e2b5d6131eb8f578297fe74ccb9b0f43a3a141419af0497eaa7756d07f2e0aa7019222a901443d4e0d14482d2994b3400f864c3de4b31e8acaefbf050fcfba7fe900c9ef4da1533f9d25c41e5ff53ae2b8e512efe0f44ceddf647b44bf3781e19285f631be3f2e09c1a44786512c5406838d19463cb4ce16f503fde7249ed752f74bbba9c3a7d26e1c36ffd6d7657bae7a71c95deb90ce4b21672dc7906fad482628c80b10f55500181149aeadad40c20a680b0d21b3507739d0f63ca9ff0d7e139de164743d5b04d7202a903595c1b6f6d0961813709be545965d31703a8276aab6c82351bcc4f41c028b967c0d82ce639882dd7d359f81ec97e8fbd6afff75dfefa44536eba8e9fbf8f34ed9cb77ac795c76e0cc5ba6dd31738c102beefaae66f5d7b233a778136b07ab0faa234f804de87c80d6a190a8de178c57bd35fefd2b567fb77ef59fe4fb96be21663d2bc487552f1dfae21affececd6fdbf9696da67d7be75ee6b122efd7efe9b3ffd4d3d5f8b350e1ab014baa2815e7b8f1023eebe679fabef950aa9b1ed91071d248203442b00d37390ada0f02c8d2bc380efdebbf9dbe12b0b3f2607d1f7a6f44d9be01f711c99f8cc9269e3d5937a8001d69fc37edfcd847aa0458471f98ae4dcd537dcd173a5102debda7c35daaf03e115e4537545b6da01a1d25c246fc2a38ee03b4c4b36960e3e26617b704328593a69255b2be04923ae28f183329ff47eadfdc37d84f8e8d1972f9d834a0b9ac8eb497e208fe45954fd49410a5955f701c42230290c4ad6a885e751831d05b4070285a23d9c37158cefc7c52fccfe6a956c91aee97bdebefc292176c8ea76ed3195688fbc84ed51093c1cc59bbb6798ade2bd90d622217fb63db8d8fc60ed3fdd4f6c5ef3e9c97fa5d4a49dbd502a882f9e89ccff0e0a9cd6f8eaa128b4a70d83a91e5ba3e83de358faba9e514b44926b2baf81e858311558b9429cd6f6922f77f4832a45ce9b87fa165eb01257e103bd760ad795a25e3cae8f6ca50aeac9ece84a1c65491e8237d453627d29d62e6215b854c16b54bc7bb14a72aae8a54a72aa88cf4ec467c3e2fa89d5d2025ad17ae12be51709f1e686270ebe51b6f3037346ce2e8ac8b9e7e0a73b7e3c480e869bab076c58acdaa5eadf0a6e4001da0614feac8745b10e1dbb6e06208ec05cfb92097ffba709d7de03280756ddbf6b26af918ae5b571138ea890bed3177323efcdc75ac75a646fac830bbcfe44c08f63fc0c7ffeb6c3fbef223d9a5b3bed729c7ff426551c4750d14eed393269c5bbc287072a788b8cf62dd2b1e5e655bc0f14c7014f58499ffe7d871f7b491fb4ebf0bd0777fc5c7d57da7813a6a23d52fea16008213bff2c72ff925ea682730151d9ebec24156a8b76734ed83d8e5f5e41ce77406015e47a6d8e5790072bbc893edf512171c57491b5e29ded7ca02bbe15bda16645f6fcf6339f2b7385786bfcc4111f97a8efae5fae60dda90a560f57b00a9be76c808221795af77f89e15a58c6be471effbb1f228be22700ee61e26b6f033c9ed191cf3ff9eecdad5e92bfaf7c6df1fb6357c5b507af201fca7644f0d891b7d41e3d59857ab0e29df09ec069ed4bd11b69ce634d54bc9bf4279bf2ccf9edda6eefc5bd4f56df9dfabc825caed3fa2b980205ede0e867078a5dcb33cdd330f8935f5bcb034165af660c16aef3b0107d469e72ee215223b678a6658f027fc2ccd7a125551fbc0af86342e5ccacc256762e62f91482ca053e4587a4541a6d6cbb7685e7029f08fc38b5c587f3b25908284621bd97f8c857c758c9bbdc785c8c02de127cfe5344a7ebda43aa57fdf49010730ffee0d5674608f1d26b0f2e7ef93269e1dffecd8495be28948bf2fa6b553bd42d037c4ac1da0e0ad6c092aac1d9c8351898dac53f9fe1f7e2f9bd418f2c34ac65d43eac60fd5f81e37d759840f52239fe5e07fab57b01d64a011db6f79f53df15e2e891f9136eb8d75f5348e9d4c55f7329d66b0eaa1dc6b1131f113214c5c8b2ca659b4fd2a98213a9bd11e21b05e929a658327047870c95a7477510b85fa72d5fed5c055c992fc4e79ee22e7f8de2d78f7e6cf37e9a108be67ef5fa8fa8a9afef04482191a781a37d1aa058745d485841da64d1f7ac73da0cea70de9df2bd8f38671e74b6881d9d9c8b42d3b1e0e31c3a5a194fafc2f7f1b5b97cc8277d5f31a337d1514ba8a728f993edaae885891eda8fe8e582fe14e073751697a24ffcba3abb302aef359f6e707e5821c48b550ffcb9245d2a8715eb6ac8732005a23dd72715acc1dfaba050c820d21e478d096b272aa8c7057918b094ebd55a8668c0f869d817b033e00e0aeaac23aa8378501a53537f2a5e280dd5eccffb1c32509a90a1f9a1933a7410b1dd8c6321f362033f03f34abe3312ed31cac04709926fcac2541ef68e783e1ff4c6e95099c2298d38368f297a537436a2c2295b7494f6008b417f94c1efd7ce57fe32fbdbaf3ffdedd402b417daa9fe74b40fc9f32405699ed05986b4f3023c11ed6127dd4c746b29103a4190425758fd4f9113dae1b79db8f4646971877e4c39cdb764f5561f83ccad3d44bade72444de4a59a3a6da14158e22d1708a72d1d0e545b7bc8e1a6fe32574f402a0db2d8dceac3194d69b56cab8f4af0f94f75fffaba355f2d3c4488c7cfbdf685623991cccd7d7fc9824765a72c6e58418a81424d3ac6bb54c1aabb14acbe13385c77da4db6ea6b4028e06a0a052c017c02f43010abe1f2eb9013063029a2daf780c3c2aebd1838dd079c16316b2f10a2a0ed0dd34e91aabced2e9d479fd943f85b9990a2588c762a403b299cd26c8bf5d25c66f4f7587f291c29b5dab51f450760995bd3e8ad5432d8d634d87c92fa4bec8aad3dc2a0ab4fb653176d4553bba4eaeb6fe544f2f98af28af9ea89687d8b7fd5af003c44c13aaa7f414cd91b0262b4058f0a4644f71a3afc85412baff163eef78a11bba8d04dbac16f3fc261c8e8ad31a0584b316a32743d90c22bd9963763f4d63cd180859ca0143d1a07a400686b13c1e8d9b7fe498fff268171f6c56e919c27ce1362cef3efdff71d26ea7ad4d3d462c2a7b58d2a84a6aa10d9a87a48c1f5eb815f69deaf17cd2959833c1aac5135c0c368c0c447fda4712890465230a45848a1484fe5a78796bd54f5ac10fbfce3b0bdd6499fa3fdaa2e6306a4c5b547265a89b62aa20d50686b96a9d8fa24836ddd53c8fa6f2a19b2a037956d8544e9bac58cfe18b615901bd80a485d597a6562713cbfa9a569b9ed657bbe7fc88b9f3c2b3de5baa535abeab047563d0cd17a0a6da15d2944aeeb419024423b3548ef495d24191161b9b6551aaf1b83ce15a193fc92fc409a6d2cdd8d5c35a4c76e629a2d4f839c03fb912c5aa4d9c6a5039b69b66196661b36d3f2d64efaf932ff70fca965e3d3c6ca37adebf8f3573450ea6940d01a024df0a8abd83055c12a0a59214d713df0f5879b90ee5f3fd5bc7f436f86e7307812fbbb0556810ed57dd040f763d5e3aebbb4ffbfa582a9776b8e7f6fe766a5259afdc5d312cb81e7436ccb95787aae968308e823a4005ca703e3fe58fab6c28706d281cb0dbec067bb833a1fbe0b146d0869bbdac041a84aa73b3eaba0aef340faa3bec2b1df9d0bc4c0acc238fecb59faf9641d3252fc146939758def41ba6edcb830db03df2fca4c7ab1f476fa7e9dae6bd0a3f68ea55bd3f460a6897b7735cef5eb7d3e796d6a8b2fa8ce008bb1e4a9515d904eb2a0c5719277521464d0604d442b0c82f0f4c8e3d031fc6bcddf35ce3c94ba6b193fe4811f117bff8c8b5e7d64baff9e77bc54df93d1eda1d3994d794936efc4cd336e14f7d8bce331f9e3e9ba113e8f9969f881798cc61de7b79fa8f7e5b86763efdb7726b9869c521a2fc9b75e83a690ac6342addc9a7d6d250512a86c0ce377dfba395e74e830387e2059ea006880f0fa02aa2760f5058109c533078c541f141356f727cfef36263ec9a7c2531b07344a8bf4fd6ecf9ff5e43ed21c58347be44a6c62a605188aa31a03aa1a79ed7aa2a6099e4fe870f54901e809bd8a419ae05f37a1ceaf47a8a0fadfe6dfabc047f595ec3e067568410ec486417573fcc5cbaf3bcfb8d15f1cf676693ccf5f9b89b52fda27ccea5492d5ad509d4a38902f6fe2ac9e461431454f8abf0c6b0d49ea2852af6931371ded4c8a22850f3082b48b293c693de08a63789bbaf655fefdde55e2b7f6a78844f5408a8f7c9851b13aa688c9af6950c51946667b20d02047876bb6ab45b1daeaa2787b7ba601b7e6c59f5e9f374fc26f56f72279a42c2b3d81d3c44da150a648f4446e59fcd68be0fd18a4ac210a491d6de281fbb962e17cc9f1f8e5ea8aaad5bdfc7071f527b366c5b547a0ee83d53159e61dddbe5a51139e989e94dbb0412f502705455ec4e9b3f9d1c26fbbbf763ea62d3686d4f24b8ae418f3772dcfb4d6e10286857125af50dfda8be8aec9485481dc2c1e6fe71718252ba0eac90af43c4b819e6d42619e83f440a890d028d86b6e811ef1396fc38cf113270a31fbf877ee5bd84a7d17290ef238aa6169d1c4bd810aa492790228bca2095e4ff83c764c96de5589210ddcc0dfe9f923ccf76885516b426d19ca813ee5ddbbe67ffbad10cbe67cdb7f841f3bf5156c6efc00b158b6dc728e595aaec2614971cfa1b91e4e446f633fd4c02d1367eadea9e7b569a3be4b2b0458647a80918536c5bc2f6ee75bfdfba139c76d481f13e5372f74acb07a3e310fc422b731c38559baac3dc8b22d33e9698f9a8f83a485858c5ff4db8693d7ac5a413172aa1f6069cf5aee69a2ee6b420add9247ae1507267af26878e5b43ee39e6079629cef1ca0d3b1a158ead8fbfcb59afa4beb667d776e5c7b700f2d28c7d4be24c7890d195a7c8f24f6f8ac1e362b90f602111166205b3ccad6eddb4648aeb921a4e599e43c7e3e6e0226bfb676088b34981b070f14f5fed60eda7308685c5de9adfe1e1c90061ea8c48d584226d95481ae36ddf6ec21828402f3f3c72bbc99d2729d3ae49177de244bac8782b4285d43212b4a5f24cf837b100429664c9e045314a49074ba2e06aade52c4627969d8a379f769ba34d0eb4d486b008d938478f4b4d13fbe2d07ecfa49bf0d9ee26725d92b6f9b54fc71e73c84d5733c04600be930cb90f032411e48583d9778e24cc94acb6b8d2c1e3dd0a8e29c2c35b2d0b006a5150d0d2c175052eed465e73dfdad3482a13dc67fbe0e9d8641c394db60a88f4df42ce4423b20b09046131e35574c89f945bf554d5877f6af385f424fd4344193e7408a84e4c8a228eaaf33ef6f2479a22f8242a076d58ac2b340b2f9c3a0430ae668461f38c9b9fffec661f507afe811d71edcd0d8dc0af2dcc4864ba0e23de0a958765848ee5146e9b53c2c7d581bf240489e690d9a1407f7a4499ee90b8405b75e5b69115d33481f701ea0fcb0434e3a6ec2b97bc87f5738ab3233857dcf9d5c76a21e2fd0b355260b56c949db8dd3b907abe85c05cb26706c93396f61e35e7ed6c2ebb5139c7ba5a25853b96adadab5ea4575c83aa9c5a238ad7150e19486489bd3163fe5b943d1e858f07d0ad2e21759527a7334b2d468f16b1120069cce3ec9657036e05fcce7f9ae9d7a80d2807e1cb04401bf7ec7bffcad11d6d5fdb2c3a71d84d8e7b8c3efcabf4cfeedd250a7367efe4816ab7fe09b5a52e52df672726c9b5a9600cf0b6c0a5860d06fee76f8d883ab7a870d4fafbc4d88f7663eb73682cfab43be7ca0f21e8b8df5d82a425bcc686f5f727abe73e4822eb27ddbfdbbd3cea37a097b21a43e6f05fcd09e56a556b9cd427ba8e7790539eddc908176d015d3ba1d157d5e31ad0be92cbbf71638d166f9a17cd1cc19cf08b160d6cc65df9282a0fa0e181cba10f01186935c53012065b3513d0d2dd6421ef54990e4334544d317fd5d7d89f608a9c053ef8e0c34deb2ee33eee4ef7bc97e6ad1bef585c7a688c09e619b5d411edc234be185963dc93293f41f3fb29bd307bf2b5a7f37e8a35b8598fbce87d316832352e4d46f753008abd15f3c54e861bc9b41b9a6ae6da5406871724fe9f2b71e78cbd9f2839c9cd0b8a802b16d12480386d236835b3a44f1b84a5957dd67d99e9ab2765ca4411653168f9e880ac1353d17c5970c9ad7fe95ff13e2a3092f8dfa18e74250c1590ded0d457bfa509614ad29208b4757e2526c185b3be8024178149425d1882c13bd391adb3d534ff87b98bfebc29f08201d3073387b9ed1a14c144d2793d151538d767dfd45bb953316bfe65b767b5f7668ffd52709d17e8f1d861cefe7e387d90467a9bc75b01d7ee02853db76f8b64d2d9bb91dbe83c2aeeaeaf52d562c970ae487e7a645162b0a75df0292278681568bf45d4a57a5100e296c5f027becddbbb6f34b42b4ddb7d39051a384bd827c100c22da7d58ef50d0ec0af202751f7032b0ca40cf5a60cbe805779735f9c5a69fbf1dfbd305f3a4dcce9bf4d1c35f53c1206513a2be406f39429e33853e69cd83da1385806400e982b512e024771b7b2d06545f168bd933e87cafa0ef711e15397d5a584e90691b5a743fdaef477d9e0dda61732bc8c35a91b8784e29024adfcd0a9ce3a3e8c50ce22cbcd7a417dc44d5e07759ea82ca0fff2ac4d76f7df436350b9f5f743628221c3a6d9d0a0da97f9aad40b655165638f64f5adb48ba4920154a59b2a244735dcd58cc59c5c85de52807b22858164cdde29aa3d75c22c4b4871f7bcbafe7f02fbd884816197920b4c6408be6e469b0dfe93e1e3bd6a122a48936248b099367c15cfac0efd90ce7210097d12d372159da74704dc33380d7c5f8fef79fdd892f1f2aff7d7c5ddfa5be27966c53cb5c0a15e842c0701426cbb6b3255b503f0fd55fc343911edea7e8f5f0d692ead1138c6342bdd60148975e740cc7c1bb301d06f93743529303a1d36685fa026b3d14922a33e9c58d0b93be48ba6668f28b71d0ea9ef48cf6b3e229c4c903c90785b6204fdab3cd35ef377b260e92a7bbb957c444ada12ff9bed02b298f76f85c240855631eb085d4692d231892cac53b18aee8f135bfc0a23b5bcb08acbdd8d76815fd224d4f5fa46a78d2876d6b297d8539a524bf6f350542052894474c79f352e4bd3bbd9ce8df939dc5ede20c73cf52394b8ba6634d3c703634559e0e5795cad6b3b86395a2517c8937eff16972e25fbf68cda4aa4ac57f3d424cb554e0870af06a58b0d5773148d951b4484d8b8d503cf5a729a8d71860d97917019207d105902cb530a0cb60449817ffbb6b3eaf0716cebdd0037b2520425f742e4623141c15def90ab0667155e76ae989ad2a5de2de7f94d067c77b4549ce9a469a76ac421d490e5a0ee80c76aaec653b088c34cf9e97f2d215df8401ce2ab2a9027ba47719358fae4d1965e27a80bdc1ee73d97d7280363cd470b2d34b24ad20977267ec5890ac023969057970a706b46b62fab18a77b33d38bf342e3a2edc714c4f928b0820970fc1f0b889dac06d1e46c4f2fb265e640805e803fa4719a75e9e569053123f4f6067047d563cab201f9bb8825cca6d58dda777c2207c24f09ef1f4f5ce0df68a77cfa017ebbfb1c013d2f388df06efdfdaf3823ceb826e9267ccc35c2168c36994f9bb3eea99dd1fbb526d7fd8cc8b0a090952a8ec26e16f25b2abff7b741130e20f462ffad95e3e0a078b142eba392aa073bed2b4e402ca8ea3ca5c132717712e2626e0ce19848bf651fc1e78404345b44ede2973682253dcbe2efa357c29c45723de7978c6e312bf434e122898d28be6fb28588b02bf1a1432d5a06ea0166b05b5d892a10eae7d7da982e4c934c2a2270bdfc3de571e751cc1ad7d61c7006d29128e89b211bf372284a73d3128c014d91eef3dfdec35af458438fde74befbdbcc23fa33c25bf4b6eb41fa84c49f56bb6c29dbb3d65410f55ed2fe540e190030772e015432e862adc29d6fda5f022e08f79d1ad109df355c1a8fcab7a2fdeee105e1bd7aa249fae890b6ca9217663bf634d443488d87591f748f4ef3b6322c65e6be20c2d97eabb2e253916bfa9ef56fcc8bfce51cf9147a670c7a5ad3620c748531673411f49266229e8b94e91fa4e25c79abe8bb3f6e7821ebe558ec184fc0a143eb6ba307dd73d4e1062d74bf72aef200d9ce5f77cfb455577d61ea87bc22e6431886c426d406e2b39a6f7cd0dfee9c4832e78cdaf407746a71c70a05fd0eb7aeffabfcbf688a64ac87e32e5aa58b527e1e20c87fc2ff5f524c7b1f98bf029c013cb7136e84f017d57d19372ace89f81fe8bd19b6bd03b23f1b8107ff3909a234ed3fd93095802480a06862aef179aaf05222cba3d6d06c0363f0f44c469deb170c5b2a1798b74baacc269ef201796422ef091c0b3f55e400acf87459acbf6aacad678747a96ffa5e7e8efb9f1f47fedb672da6772c25f74c797237eb85ff14c15ca3aa68b186fcd5e8058f4d685529fe13ef2342886fea5828d0fa02d4824a96d86e31f6e8286db96d748405701f2841ae18951c5af6e976b8498f3eb075d7f3e56880d67ac5df6fa7971fd45fde07966bb77d338c901f6c0d22e3ff50b79a8745f6ec2fbfa883ec02107823c1af433f017bcc302df7b46f39ac5e995e8572fcba03fd622b7aec836f0b1b07c21c71ef60c8bb597498fe8d3f372ba37e9b93a7462d2d7e30296accbda83f38b3de6c4c5ce9329f385e83724ffbd41d8132d440a97422358f3d36b63fbe1f7fdd8fd488736427f22410865332f8719043aed2022c47efbf5abbfc0f728677a0fb77ac5680f53ceca30ffd0bc40ede19af3846c37a3ffa43c8e8c7f2e209f14d21dcbe8537fba5abe397df2145de33eceefad62a2ad3dc803e3f2abfb6593afeda040c46c585c2ccd36560fc2f2dc9b9966eb253b588a0e1c9a0c8f24162a08c73ff7cbbb2bdd05c85ad0f9efac325617449d66c23a5639ab3d0dbea641ae3d8f05bbe2f7714514d02181b002b4670e2fe88a4ffb5d3f60cdd84f55411d09ba1bfd238fdd4ed685848a7a2c8d32ac9e4b9a4649fdae9e2f6331e6403e3ef053bd82649fdffc3c7849af87b8d7a06f4b0f1f8aefb6542027af20a7e741af88d18ba5931af4e32ade4dfa9c5faa7f60e9a93b75c97cd6df72a8e3f93b465adfa15ec00bd5fcfa9728bcd1fcdd61e9a4d6f451829b7a45189db8b5ad434eef3fbba5e43f756c8b4e237a8860ba78b0504f8d467b9900eb3f536ead72ccd2ade32ade4dfa96ba1d2f58706bf23bd17b8a9a832be6c0e68861b185aeede181f4828665057b818ee58584b6bce9e62ec2e24cf4d8161a1880ae39d1fdd276c5dbcbc9632005427bc990e2a0ad1cb0c543fd97e6ef7a4de36d130616f5d804fdbbbb5c05744c3bdbc4797d80fffd3f9cbee8b8599f8ae0222057fc083d26ad4f089e10a770deef3ce9829ff818d68be9cf27fdee70d23be22eef21d0a78998f837e5b60c316b4b057260f1365905b9cbe859166f1354bc47e2e9f1c5775e601b9a97529f7e921027de7be1a167232d579f7487d0b43ef12e8541dc1782c2e05b68f045dd8d1e07f43c5350ba504efe7eeccde79e77d93af9ef13c45ed1ad3ef8e2b82d2943f7a7c2931944d47f71725c6ed0b757bc9bf4f9e23b37b439bf504ce2a9a00762bb9abfdb6eb26bbb7820818a5cd37388b96670d99bb64485ad32996bf05821a18bbfe732fa517cf9bc85cf2d43e8494f90b46502dfca810af5f862382b64f2980209584cbff7cb05249165f528f195c0533f1b7ffcfcf1f29e8cc6aefe76dc3605109714e102373d078ba5ac71a6f8a581c02df1723c1706a60660913778e31bc07e79592a8425023b2bb0013f142b4a16851ad8932d59057911a367d983ab193b35103daea822f1f4773c6af71f4f919e65dfc543f20ec0669cd1839a7cf81e60aa89936209912221cf85425e3491a937050b356d17dd5fcc70f270a4e733eac007661d7cb010690569a3afec23e22315bc3d4cb9e35951aec5a3b4f45f6cab1379473cfd8ddd934cd3e70616e317868637513c656baead776d170f44efe1138e429b02a09013dfacacb995c9969089c059dc7c0faec69bbd5b7c05f1fdd3734e58892c283d3162c2d4bb5a12fcd2c4f9d60a81fa8d306079a296f91d5f1105680156437c5723148b5fb752fb53f50dbea7d698dd78d81a7f5750ee39c4fadd05ee014f3cc0936c6aa92d7dcae2b2a73d2a3e0ac4819bd002492f3e1127d8db2ddbc0b9428dc9bf527c94aecbf7648b7920263dcb1e5ccdd8a9c1507cc2b6075758bced4fcc87bc31a0cdb5d70871d075c74eec8e02e1d49b14d46772bf6f42522ce499e8901729148b22e1e9d581bdc8f09cde2c503e575875eb65592542b47ba6f30f53fcaccf63c4f4285fb69051305dd754a4cdad202fd2b849cfee512696e3a0a7e202cf6d8a5f31d1c3fe0adbf2da3e1e08d22f93e6b9bbf87bb28e4de849789690492c5d4fbd47d33fda2bf72deb864bea3b9342f09885ad435254214e959c5fb1fbc85227c5e1e2db23806ee2a6f9dd5f2a9fc71a8ad347c4faed748ed7d3af8309780eb1d000ad45259ee02c13a8280ab8f20ab7af9945f07eb204bfd8f80fb75ff03fe2d7325cc507b314f96ec17ca20fac65f01046127a963db8ec215e1682c94d1a8289e22963530677b857887edf0e6db8335d88c38e3ffee21e384fa6052af65bdc02d84241522cdc43d16b26965d6203e305502b0e0a8d49055238fdb653bb0f979ed28bbb757bcd4f9f2f715ee8f65882f6e0f34dd06041fb24f128f95a46cc03e11e0e4649807e62390e1a5ce67cc63d4aa2f764f343585beeda3e6b2054afe1467fe09e83d08b8ee676eef68e350752929089ece832e0864617478a2ba396947ff00ba61ada6327b0691b5b14a73a09bd5680e779e8475f11f1c7bc26333ca24020ff5f2a5eef79ef86680125b7b88a580c3f18630e834ac209d4baddf5d0666ebe79803877633f3bc9751fe847a2305948b6b99e74b26dec9bb9fb305fe3b32a561a07c9f6e002fdd0b8d4dace4384e89b7afaa78f7c23c4e9fb5f5a7b1a0e386b3950c116043f30210f79e93513be2bf20d0cb24d2f7d7849f7478e3ffd7ea93886765b3de323f9630731b47bf720bf812404dd1ecc80b184f612242118f4899e97dc2032e927db43adb97b703de5fd7784b0c46cc46e5d8be7e069975f291addf0dc42b2c41a6d8b60aeae80a7b44ad3427064574b8ba6c5b256ed298b444f88982075488a2c6eaa70e0277a8581d3d0734d7a7ff8cb5520a03872e37e6f2316f81e5bc0e222055014908348146fee04ca43037ccd8c5b7224079f6b7f708b5c5e778fb2b0546b240bc942ed7af65838a48b293e6e79ea106f20a461d00f78eaf68a77e0dc830a846014bfe83731dcd9ada59cb8773f36bbf2ea3a21463c7ddf19e3e70b31e0f1821b7ae3fc9a561f29d812e9eea460d20628988a50570a4261742e4b886d43eee317ed7e5fd121bf0971d90d250f3df78b1caf43db9c35e942c9dfd3de24bfc2dcc66f6ca2e7910bd902f1380f19053ccaa6fbaf191ea5a2675df3e3f4d5f35e207984fa93e80b54696dcb6bfb78202a5f3f567199118f7bb133aefb00372a30636743377d16b7ceaba74ae7a19e12dbe1fcec691d3a8be219237617eddb8357d4435045b6560c54794b59497dd8fd432d1f1f69a261fe08d712cbef6140f9fd5d17ec7370caf3521fefe13c919515df7f7ac700d55fc351491d93032f1ea709d38b9d05ad26d0b1ac527832f081e8df91141aa333d959c5fbeebadc6dcb5c2f0bb277696237e5aaa7ae43523b2178da13a309c5f8ee0467a687d5f38cdeddd859a127ab700e9bf4b5c2e615d3818a778df39d1acc7626fac18af728def2f836030e5b2f44af2f8e7aa4f4092146653df8c1d37f15e282c231df5c8b1d0c5a2d0244a1664b759abd68f18282a937034a0fe592631e1d7c459510ff77cce383a7bd2e445bd1f1a419df49f95a1b7a75503a0cc23c11dc59a299fcea0aef9ee6fce2d17c633933ddd67f7afea13539a2ef592bde13f69f2832e905e49855bc6f9f6bfb1412aa7aeb5801190aa3b4c657781f35e0e20ab2f20d3c5b77101540914b4f03361ff7111eddf2305921e1de8d879eb72f16d129e64f15d9fa9acbfefe6192fbff53ae8f92fc5db6cb311f9ebd60af1ad99eb78bf7a37503e4f9c50adc14de2d20076a20c6e440e1b142420ff7990a07f77ba4905841a9c70b4aefa3ad25b7cce5fd038584b1d0922957f9baf06f7814c60a66738de79215d6c60ad1a8107338701a0fae41cfd516aa493f9fb5ab6bf21b37be5cf69ccbbed3e097eee3fd96766acb8cc373a4437a5fc70f0b7174733a7aa00d60abe3156c814d4a29d4e5af9d844e4be97d81bf13c4a54e873ce999786748fea6249c0f5ca33decfcf2f6a6423d935eaede5ac76cdf228b673256f727d133e42ec0afc7f865fd17777e0876d260723c562b14f5fc96358b9a796d8f10962d3d91af69c416456d2e3834344fc76378ac90109689b650c9d20dc7d3ef94beeb817b3ea11875c280b4a8075c7b1254e95966fe5ddfff9f76d9b6a40803ba42b4df6187b17bfb039ec79a7956dc1ccba26233172d3d1e6ba6b52d1e6a60a101f142f242c28dba10f7b7adc169cf21183a0d83cfe6b5838ee983fe1c331925c1e22dd133e87bb62484728d1bf43c5bfaab3d4b8cd3a7f18bd413215ab75690140779202d61886905223d11ef786f98e38af8f4e508e8e536c92f0ff959d6209286b878fbdab305c3c00d7a4d842813d3e7fd972cc455a45722b7830ad93e1e881bfd87250b443758ac9030acfede74fa5cb0e159c7d2eea5ec2c6e1e836fdbaae3cabdf602b32c2f9da71386b03500df84cf766de9ad1bb6db1566d055c0ffbe56dddaec99fbb631108d81ad073a7990c9d6b6bc246b5b34307921a1251dd87b5e3cb7e91f1ebcbc87bc1e06dfc16cb3281ea748c07792c55b7b3b28fad981f160d24b9a7cc2e88739ceb28c38bfc9ea5402fc0bd7512d215add06c8d64674d616d646a2d95b03bdf7fd7115e731c1c30964b599fc06179b13f2ebf15dbeedf38da297acff8259a389f90d26fbf0fe2b37e8d9d2dad11ee284ff922c2c315bf0ad44127b0e7393669944f1b8504018f7299c2fbec7f61c220f84776c146f7d7bdb3b7aac10a2dbf13d1677c1eeb3fa842f2a80a274c33f3168cb5b4fa258fe70575881f86da1b3ae3ee0deb4542152f35bcc39cd4f948d0d94849e43dc11af9128e495d83afb2760d1d144685a746582ced00fe3a98496a73875cb16128a7bbdfb0cbeb9e5e96a45926ff24d7c5a166f93b5c31cdb963c4d7b7e49b72bdff48a69d7a0a7e983de3b6af342ffd28be9dcf3600ac42f54f4da791da2060ad10b7a50890dcb66f29bd4830ad4d524e93f9b47c9f9e51e6539a3c7e538d7a4a7e917690f15e5cfdbf2da3e8be8aa5a80bbf8bcc17ab22c137b564544ddc77096bd2326eb89c7051ddeb10acf15f57e7efac1ff1a784efffe8ae71014813e9c9e200e8cb21d56af3d8e306b048eff512ebee9605801ff7b4fb8f0825f8ff1dbe53491bec3ecf889c98bdec5157fdc11afca82b285063c6671c506ba69d1f56c5e41a9b4d80ed8a46fb75df7a92096e6db9eb64c3b21440c3e83d966a621656b876cdb963c8c3e4fd74d56b0b98915d3090c41d007bd7e5e3f9297409a2f656561f13cbe2051d26deb8fa3380f246cb60fe797cb41805fa33db43c153143d5ea5126996f2ca1b200bfd6746e4e1ff492ecc1e59df85f12c212b3bd68e0c76ad9101e3be33ae1c014b68a595bc884151226e85885a363bb84ba5d3be016a93486a64ed7854fb0a1f45e40d8be3d85e5a9071409ad89b80cfec12e87efc61a075b17b7f5860d4b608186032ebd61917bf602af307b2eac9eb3841ae65ad6cc825b4e6ce140224a0923cc320ca62dbbc04d791501790d839ed90e82d19fccb6e4b1574c1bf4032118cfe4d70b564ce71af42c15d3090cc172e08a5e85d06748a691e2a050d5cd26d40587124a0fe43d78205c514536915fdede241711835f8bfc26283f30e9894df328adfdd75c8f72bb5cdb672b13da4a2412fd816b72c287b2421f36303d9bcb99bc90d005ce2d26435052af4bdb31234388a37ae6ffb92fb671d78ae358c0330161d3eaad1a6837525220150ce2f73f8c271206c422ba5e03920a73f8f9b7add8ffeff2df4353960dd941042d509b0270931494da423bb64a6fbe66669383bf78a76e5a2358affbc04f389ecf80651bdb4287cb6b79423eada138d0679b516e6cc5b4675b1b48bab6a1432606fda46b91d77ad7fb7b6039439defd26090a552a8ea2606e31488785e4cf67fd7f4b807b599fc7ac93ca864060cef3fbb47e919f4994769edbf66eec1e50ddac2e9e9cdbab68f07a24258c1c530d352a0dd4bf9c0d96897532f629207825874924577746cf76107655d7081101dffbe53e7b66dd52704368fc3feaebaa2f64605b52281cdeb44d0062ef0dffbda485801adf890beec2b9094c753d7fa0aa4c3fd3bfde94eff00a172f1564affe4ed99c022e7169dc23736db2e5921214da052856c424b582fef3e5a03b1868ca278cc80015f8158b82d04a3cb504dfa939379668943880185cdd706ac21183e719af4ad15ef9007c775a6fb85827be51c7af8ae38ab9bc64b2205b2c794fd3a75fa428ea10f4207ec382e48cfea416d24bf493d289bfcdafacfee51961bf439bf36cf3ad91e5cda10f8ef590351b94bb6c5256aa0a17ab3bda6356f304bc1f024122c62366bb1953a36a543daec2e63853876af734f2b54c10aad38d2b02d5fea01e6ef7c9b6bbec74f4071b8e2f779b9806105f44141526e46f4bab7d5e9fe00bfde79e2e8a3134c1cc916592d9b5a5a074a320b976fbe19b618145b7a2b45a4f1c6f19dcbf85696a6cbf6760bc4c293acedf1104cbe99c5d6ec8a69aeb0051b5fd6104cd3e9a4d6f45ad65fbdcf3ff9a2331f9672d323b4418f17185cbe61e6b4748ef3d73e8ebdef9c23fe7970947e91734c7c7b04264ec3b0b4f21b0c1945e2bf7b63f70cb3f65f528fd2c2afcdb34ee651825fe97ffc776c65e2dd2d7a4721af4c1ecb2a88e94cf4b0ae4c0e1b38cede8eab10557fb79d113d5c552a4baa668568cfc0da48763c2e5008d6e9cb9dc5e07b8438e1a00b773c1ddbb7b73819f0604054d2ea5d4829c445a12d0c140747e1d2d2885e6cef96b8cdb6d94567d993a7419e07f80d2d938ae3ddfbfaf5bf588856b9e9a73cf08c4854d14bfd659c711fa8e81d8afafd7c76c6fd4876a6bd3ecb5bf75786f13e8f9d40e9e9c56b920385931c3cea6d4e0b052e6f847819fc848defa509295f2bb8c467f1f38ae9226b653ed157f42e853cdb2aa67bea1d194cfac18a7793be67a9c84e5ef19e983e3bebbee3f53b7e70e435429c7ffd9dad1f1821c4d9ab8b6eb9f45121fe9c5efcd5e819425cf8e2bd839fec2044db833b9d3a647682f618da7485b7955fcf6c0fcd6fccb04c5c419e6c070cd67f62b296df9e06fdd8f8189b905f9b7c8c35e7c9d859ee6cfe7ac74355cdb6bc52b60e591efb8fdfcb66bfa5b9ddcf962eac13728ecd2c88d650288f24476c88c230f074f10b7045ab549ff0abf032e039f821ac70799f898f067ea6889ee2e15c2556e1ef61d051efadc47bc3f2cd8a8ec233804744beff5dedfb76e9d6e74a213ae7ee5a5f394988851f7dbe68d10cf58a86110ad2aeb41edeadcf032907a423631f071e018ee771d8e6b6bbf07e0795c2b4581e2a54d04f1638bfef98ab0f962dd7f6b78ec7bc395dfe385a8c4af763da6384f2cb72d05ea3142e9522b5e7e2283e1a7bf5e4002f134abdf652fd4167d3cbbbd4dbc33803ba549f5c3e0acf293c47e192bec2d31d17f8283cb7187801de1fc5ab0fdd307ac50a213efef8d59ff1d9faa8e2da5a138f6e06e9e37d156c64e7a0f857f7f483a674ea24db65c74eb346668ba0bc66002fc3f7f712fb01ef85efcd029f6183ef0cf05d06bc12f488fe2425cf12df318a4fd5f2aae88d52b8ec0793fe18d0cb51f4a55fb418f76502a7e7e800d47483df9c00bff0cbf57822fa99c077c4771ae32bf5bdd4b6edf712a275a4ddcabd4e95704d7af77dae95b256975ad9b95f13ed3117e335037c4614bdc0f81d13e0b757427e2b402f205f49e6034bffc9bf621e73480ecf30f8b5cd37acff02f3e228d02bd6e36314be338aaf98b770e70f3e1062c1ac590f2c562d163b829bc97775b582fae454da5d3c817c1b5784ffb03d3c90a1d87a90a5d906b22b82a10dee1a96e3b9309e4b1cda2057317022a1356b83870ccc90045cccdd4ee879cac5efca7efce4eca3fb623b6b7e1e8276d1fb2ba8b7af2605cbd748a8d23b0218165be772f13e87bd3fcfe4cf57fc5ddbef3dc6df9b28fdb58e6fded53bda5e22e53d114cff8c850c9565172cf4324353d93c446973e193ac6d45588832991c3c4f6b0a5be6f2b2843a562cd9f6dc96906c732ba603a18c9eec402916e24a5a316d5bbc4d16e22a67f42c8bd9942ce0250b716d6c7b3437e4d75c7e75882b69ba6ef3f82ddaec1025e79f3c26d7e097876ab7cbb53d16d1c77b9fd5bd99a083b9c0bb1b5d48e8e23e72595ddca7f06c1d7337cee26e6e0c9ec71c433d53f6e9226de78ce3bb0d3af21ef5695a81603150676ddd68427da00ecbca7278e8886082b459f5edcd83d60247dca60b24c963947c0e5a3cf2067fbbee218b2ffbfc057f73c4494edfa3de12cd99e89ad79e939b793265b2b5ad5c8db3b52dbe28acf0c6bf37b6a4f35e6cd7a60c49ab3c85d9227fa0308d2dae0acbe2ad6e4fd09bcb0e94d28bb901c3caa4dfdcb468c29b5b31cde421704055330d8ba4ed212c868b7db1b9697e2301c5b479fc52d2446ceda579fc0a937ee0802a7b01289eff2fd98db7f1096f8775eb445c077b346144f1e0a2289b5002f504cc73b0580a34619162b26655d82c66b61856fdcafa57e7ba427cfaeb1b67bf70b6fa369dc74ef03d40f240a85e843c0fc2c903f81a907b0604052e97dd9704ea1055317b1f16f77581a4541c7f1e72c327fb4d1162cfa507b67cdf5fd4ac087903fd4a61bd379965719c5b5e490abde20a09c3f8a6c472d05c4545167e845978ccd3ad3fa2eeb9eadec2bc2249f0262e0fc71a5b2d455abc1daa0bffc2e0c79828ac3b28d82abc7b363dd107dbd3b2381eb46c153ddb1e5ce58c5e7031dbc57711ae9edff40a72b33d62f2602896048bcd090dbf00bf76c5caf92d4fc82fefbf60ba6ef3f8b5f45fb33dca27bd89629b5f5b6b0d8426b04a05e3d7407a3dd9efe5e356c8bf8543571d70801fc3c4aa8583804d1831c0a93ac61d8dc43b154e4914cf54e548f2398557a23c29ac7087ca95328147800fc28e5548e795cfed07fa613c67c64623c0f3c0970bbe4a15bee0a14fa68d8b08f1e5fac805f3a020eadf04a4d8e277807f56509f6088a9454f31f466ca72c2d6283a7b8b26fcef01b13641ed9b4c8184ce33e984ba034a7a47be70daee6d4f12e2a4ab463e71d96142a44fecf0b709fe1ac7c14e64a779d176516fcb75c64569cc546b0cb27d5db4534114afd46b10515cf6978baf527804789e8ebd2316ec8c05aefab954cb41947bd98b613ce7e0be30ee73709fc2a7ead873897a3f62fa313988e26b3bfd7cdcbc2384f86cda9b8f7ddc463158f7a882b5470222565cfb06fe8e359006f49fb748e82bebf4031f89ae81d477ba076b20fcfb33812bf9cb51f2a7e5ab92be57f99b0ee199c023c01dd6be33f59a613edaa94979d5f4757bc2bfd5edc9fb4fdb2b6183df3c46af8202ad8cdf4a920f3d4e0b412d8cbbb3d03a267d27497b503b64425e74fb307948d61ec46fa5a4a0e8d1bce25af87512f2cbfbaf02f4c2a057c9f905ee30fa167e05f1e7825e29a35fa2e8adb8675155740d64d2ac8fb6dd1ac8d6522098d8e237d98bbe4e4e643d5fea3b39574e9c2977a6dc72b8bf9d334d2861085c05f06c35409c990e2d299b1d90870e70f15ca9a06955e111e079c0b1062256811b5a2c2c8580d3a27b09f03ce0b10110c5d79df8eb159f7d26c4b41e13264ff2f320de12f7345cabde5c3b5dc1fa6b00bf55d0efa0837f1b58d1b1a310bb2ceade316589103fcc5ef8514d0d38a6897e0af08780d3444f0aa01438790ca4602a4c5cc3bf03fea4a01f52ebfcf42ebfa55d20c4397f2a3ef01cc9ef6e55fb3e3579a5fcdbcba97d4ff987bce91c71458bbfc60df0d862a65aacccc7845c02c59ca7db4f097405c363eda9ee77f17c312916a8cdc040b44ca495f85a3db08167a39f676a3988e0bfc46714fff5c455b77fb583105f8c2f5ff3d93fd49db5e8afbaab814361d420345987ddb31a707e858ea24b8a59b30ffa47a7355281ccefe88cf44bb91cf6fd3401e4e27b573b33d577e9ef75f1bd99e0bb047c67826f931eb56f362912935edc045890903e53a8b23d39fd4ae061f05f9190bec3e897307e31e169032fa6a8ccfe2b019ed7ccf6d0133d53845c1e92b5472c29210b6f013dc8fdc6f30bfa307cb46205fd08a36fe7b702fc0287e2d2e383d1cf54f47e882cdc3faa40e67e3af18faf403021ea45594c807e0867df1ffa9cd2e329f9ea7d53db0e9013999e504a9927518a0ec947d64aa5d960b109857548a5c5b219048fc645964e31d3e415014b44e198f81a3eab7f66cd0b424c3ff95f9fdcbaaf101b0a7ecb589fa9beab1e618c3a84b2ea4881c88e69f9489b6ffc0967c053856f4fbc5188aea17de6de9c26c4411dfb2fec7982103d4ee9dd77c3ab422c3ce0f31b964a8bb7eed39a17424fc4dacbbf52f604de9de15024baee64490c4ffd6b8b23529f136258f1b517f4f95a7a1abd073f7589e4ffc05bf2863f34d73f052eedecb37c3ed39c15ed4f89b64b816a778b27912ba23965daf2cd648adab10ab883fb145e499e04fa23a6384af01c5ad53291ba946dc7147f29b27df2b545aede93670ec4e5950b2eae9053e4bccf663c3c1f1e07f5572d2910f2440e347fd7d975e441ee216787d107a5777e497a6ead3b7d3c72a4889727d56e427bd0ea7b33f44451827623b98f44d14aed4147c0b7c2631e4821be7f1cbe57194236455dcae897980a35c06f6c622b01ff9906bf79568fdfe4b752e305c0897ea6413f93d14fd61ea4b8207f09e43673a3daa342d3e386cac6f25b62d00b7a50aed11e8e95dfcc787eb5e27341cfe251ae7865d15dbe02f9f6c64fbfdc760a24d572e356bc6aa755fffddb3f0bd162c7562be37ff7105384580b6f2835b8171d289e70f0772fda615e9ec245ae4713be8a090a86e7295c60f15c52a5fc6b81f7e51a389d1406e527bb279a293f7b69c583e33f1162f5c0a5ed7e3b053c66016262a7a36e756260b110832b2ffde06f525186faa4387d7c8fa34244fd8ed09e29b7f80cb59bda39922fff71d6f9452f2e6b2f3b2fad7ecd47e7caceed5abb6ab69c98aafeb5e18c6fe64bda4b1a4eae7ad727ea7cdff896042f88a57ec7a79cd9e2cbd633846895d2e6c17d0e90fae0a116bbf798247fdf3ded8ade55f23d53433bf4f0155cd851f6f60962a03fe57858dc73cae94b1d8aa9266ecf32d51f5e2f6f14dacd453ba9e9b40803b258b5a4a73d00e0346121e6ec50619deb94e339d5af61e0aeeee772c66739e353e143892ffd1dc5ea6e2d07517cd590657badf04bae1e93ffbf0bfd76392079162e703a03fe13615e11c05c5f8978ca4fb9cfbb25f66b549ea254e4305738d6689c71e057cb25e4ba58f11727e70aa7f6cdc5f3114d4f18df4fed51eed0da05b5a7490f752a7457805f4eafc2c403fc127d97f14b6301df238a40af18f404eb3f6a8f5cc66fa03dcc792081dc6e647b00af30ff1ee097e8b949f80db3792af9bcd524bf02f22cf1c4f489df89dba390705b792071b1fc5d2ed8f352ffdf6d77e95c71913f95c72c9e523c0edc1a328944a13d26a8f03ce6499026cf77a28122672ad64292844c7e7df7c7a73e94137064d65357bef28a62b01e057fb51d15a41879ed55313cf7b6337bee2fdfb4d3d2ac95637e94f416398f473d31b2204bcc509cf38833a3bd7c3e7476ca91d9274a45b0a4e55561c941ebf5e9f70c1922e19eed27f99b15b679b7dd9567cafb5aa7b7ffe02ce9f1b4fe579b7f9d2127c0d4c6160f1c3b5c3e7f7aca80033b487a5f398bba74897edf587c5f217ac1c5f715e2fd61b49fe939104eae7d01428a654d87f8b4255669099938da9388eedd2365a22dde17c6fb95f4649a9e83954f41b8b6f00b0dbe9805fafee1cf1efb9454e86bd6af7e6feda1e837788e7aede311056bb06b56dd3205297b8b3c11bf42216bc881ed3a7f293d909a8e472a0f24b036e002577b15e5a8ef6dae076db53c4b21bff9e897580846b5970ec1f0b5bd4008c6e457b72ff3a06cfc06d6326c2118e641c5220a8e41df491a51803c680f44d12b65f49bdb1ee411f39027e7b7c2baf6c2db43d1b3785071f356b3f88df3d84bc07f5e227e7f58b06848d403f9eed367ffe3ea40b42527a7b20f1e78ee81cade92c98b1a2e5fe81f2c434741f6d495a10a1fe8758d3e333250d9a94ab3f22d95c954e1cecfe2a60387eeb69cc5ed253e8bbbf2d239e203ec1e4a0ddb8833d21b309134ec8bdfbf92f3c3f893bbec7b9d9c585e3ab0c758ff88db2fbd0bfdba095e912bf9322be0fba0f29e57d2db2b8733e2f98c3be33d17f4a892351b7fa7f6cb36db13672bb3b3a1637ca25296ce92d7edabb34050290b9b932a673d9da5427c16197c0ec711af492a86359f439354bc0f44ff4ee67c2abc2ab476dc1239757fffe3d7b7fe8423a51a719a3459f3d8a54d3492cdf70c203c138f56e38c424f6f77bcc794a79ec0e90cf2817a13cf6655203751e1ed815ed315d3aeb562daa43f3640dfb2434380df9189f8f558e5bf673f233c71457673e561632bc8f32ded413b2024ab20f72cedd133d01e43f15c86c97f604705ceafd11ebaff680f35be6303e7f76641e5c9dbf0daca1e08d96021dabae34f7270ded4509b22e13e27f72eecf6a1fcdb8fa9837b5f29fccad982e83dc54e148a7f8a0ba37095ae1ca7ca4e552d9121a87254e13982b2b6e6aafb6091e2140b0ac188bdc411784ee0b9cc785e79c57bcd37ebbf59f89d5424f3befa753ead6d7ca9602d2cd4fac142ec11ea35a59d9c120f7becc45f1f978a24f459e8881d2e13c10ad45845ee06bc4fe17d54e5bd3345bf3a33099f39f17ccafb72709fc2ef465e382a95e32a93d3f13b55e62a3cc6673ae35355ca8e4799232abfb5bf8837c6f19993904fc2c7003f5074c073613ca72c39375041adf0d1492adeff09be5721e9220cbe4a15befcba6febdf9828c4ece5ef957d75bfe2a516753bb4585e8bcaf31aac79d41cab60dd170a3674c6378ed6df2eb2661f98d7e945e981ccebf8eaa874115be328831c0f42bffd13df5fac2dfda62b90b9a5cf2bc8ff097c2ea3576aa9201f64a9c8d6fc6afa838027ab984e6f92dfa9849b15d3baff908517b76341f32ac87985f7665690cb7e1a0b3c2721fd58c57be2f688f19b6ed0cbb1d0b3f36bce07d47f15a09741e32c31bf2b672dba3eea814cfbec95641e48d56b0a363c06f87b5b440fd429c0e9d27510d2f3d9e3ed035aa7be2f44cbc5adbbff692711cc0629c59444698a3cc445e9bf3aed4de17169a04a40622118ea10c55d8e0e7544149389171bd3fb75ccdbed2d217ec95ef1d8c77708b1f6b39feefa0d1349dd3e42b45f95d1d5df96fad813fef2d66d2b84481bd36270d613069f3c64e02a3e3011c4421c6a5ad2218924d966b16c1285f345ed4148bb8d40b16e6c9a2de793f89aaa27e864a102b8f2ccb5a750046d499163cd0aca049f25782e137c2a9c87cc4a11220a2344c4425c9f5ff476b749d2535cf6c482c77ff841fd81b2af74e88a14c859c0b1cb320dc0c67f29a8f7f3952dd3ede6ec99edee12a2dd1e9d0ffdfbc922b8784bf254aadb75a6c91f5b5ccdb32edee6b1ef2f003e135f1906fda8bcc5a5eb2a7ab6e403c6afa45709dca4b7b1fc9201a443386c3cd8b3ee4cfa7cb19916edad212ed06f667b68c5c7435c443f9875d534bf791b1b924bc26f01e805e60393dfe58bbefdeadd638458f8f9171f5562a6ac4356282581105ebdb3820d6f01feee14485801ad402a002b01df11e2a7ef97edbde25669c1753ca824da22e7893fb5e9156d10377a139d3d3155ea784533338a2749b3b5d601500cba97eee07cd06972a24b7935e59bd62708b1fb7dfb5dd44f7a22dd9edaf74f6de590dd6bcca1693dae1562ffbfe4b62a9478cb35ad77df7fb89d4f6bb6190db05ca530e574908ff76781cf30be2f8bf19915dfda4eb06e057b046d629a2de773aa4e53dc0fef0fa37d2b4c3e2d69955ca1e604d2ad238ccf089ea3892d62f019cba251783e14e654f24415fdba236b7aac5e2dc40be7dc7be413d270f17ef56eaf437d07d5799002a9c1e697b5f38123cd9a62c58dbb8323173053fed6507fbb9f7db7dbf2ec97aff06dca2c35c429c9404a53259e214b14dfc9fa3fd34c7f4dbab657862c2ced295aeb5f14fd4a4bfbf2fa873cbd984efc6736c56f5c9658627e0ba0e86213a0a217933393be3d3d9ce8170057f4820650e6c6b4475c9618975b17ed53b091ed5100fe938d83e6f14b6bb781f9c0a4bfe0da99f3a65e2ec4d286f9e52b919e54cbb20cc910aa56db98c6d640909efefb5320d4642e704c797e3a6af51deb3ef7ffbdf7f8c3e775f33751bb2ab5dda17ec8270c4f424f046a00264bb30d4c287c51ac0013dd384cd08360b9694dce3a9ce7bf0f0c7dd5e238e991fcd0fe929e1749d8b7e3b707a609913a33756c863f84c9420f2cb6f1c2246dd917824fc2d57d194a6126b0f00a0cfae1c0c054f793a7528cb45b72bd791aa85600cc62aab428d46cb8de3375ef96e0b94cf05982f6cc447b96804e26f82c019f0a8f6db2478575ea3dda1223cb0b78d0b233f99c4aa13933bd7445d577f3df909ec55713df39f1f34e8a73aaf3a00156f30d202990f1c05127528f901729104ae3f525e4b76f574ff57baee74b474d1979bbfced5ab14bab9ed1f62835f82b259ccba9ceae528aa61272a0e5ded24f836893cfa63de88d586cfe7ff2be034e8a62f9bf672f9025a380ca9d020f0e13064cf86ecf848ae23360fee9617a2afa147366c02c6605b31ea2a21c2604c4802c0a2819942808778020395fbe9b7fcff6b76a776a76d8232afefb7d1e65efcdd4f4f47477e52a1c50011254d0beca49b2ae0a7d125404ef9918bfcf3ddc67ccce433f27117ebdfe0dbe60f765cf7c308325d7ad12125ff5e7230ffd0c8c9fc69bb1cdf908fa7eb94c5873c5f83de39ddef8bbc73e3d5433e6f3963fb601ebbcbc25a09044d888fe9681248110646f44d922f287dd4540d058f200e1905e596e29d8666d3267ad3b5c1fc80736f8e6aaabe2287016473e93ee3de18112a832c9433f870f428adc2537d448b41fa43291feef32e29d38f26c31cea481435244463f9775a36661e7f838521a678e679c7ed5066da47cf469fe32f17c332e252487208e890f408cb3bb6f434680c7f49373baa6df9539bb7e98a75c739f509df954040104354bc4a9b884798c52e3c6e7bffa8626186b162c7b6e3d050e529c07241092344a8fc7efa4d26a6d6005d2f53301810a8b332de8959655d079e3156e40696b6b73e326f1848e37fc5d98475a8761338fc954b13e158ce9e7132324f0258d9816eb404a904ca899e3eee1c15fe8c59f34e2bd95c9fa54797f45f196a3f461f65dc9bf574dd487d8f95b2f58a219c9ada91b9fff4d4b7c459b373dbd48cf6fe5191543369cabe77a6de58325aeae3ed77ac5fd8ea14ea189355c47e92a75a575b54a24a1da78cf1edb331f715e6211dc4784c9c67d3db6673ee2bcc4bcf882c69b13c0586648fcdb96287f9830e4990fd3f51a5e5834abe41ef3a07214ee6249041917988020d0b90281d0aca26d8591dacadb0a447fb711103c8854587c6481907060a1fefb9211b316afb959a97ffdfbb8369df546b7daa62c38f0611517482874c6d55599f007659b87b131c402d848975f88fb6cf4cd824966832095c900783f7487e4e0e71472cd7d01075f06a78e209b407fbc5f0fbc9f775c4c0004472a5571745005ab0a3230ce3ce0317dc93111a1ca86dbed14b8ddfa360c1f505675c669e5e33b74e5f9a571e68871e6c48f3390a092cd0c81849b4e5fb376c6e74a7d73ebbb978c4092ca72a8a658f280c44184830849590b4018d92b8719c804041b8cddd3dd00d91b4f7ca3db3efab7f7ac051919caaf82f1dbf4e43a357d3ee8f940c930d789ef84d43cac8ab5b62d41c7addf5c8cdaf6e0cb912a988088691530de1fd538373ea9f8aacda316ea03695561c1bd63aa94faeec2813d5e68a0d4cf277e3e65a8dec9bf2c1933e26b3dcfb33efbe1b988be73ce27e3d7fcfcb35273c74d786ea296e0667d3076dd58bd4266fefa7dff516eca99bc6f2bbf98a9ffde64c2eccf349e0697343b75c3adfae8da2f2d9a4d2aed98f470e30bf478d65b75a3d9af99a14c12416e13c1e1ef24f75726e623bc5df3919324c096e62ba39ab697dc6d4b50554d2aa7b881c8911b06bf936fdc8d54b949f41f5bc714208bf5cf2a2c100eb2853001a1144b11c00215d076b304e233a60f042c04a4941c9a13699ed2face559394aab5a25e2337ae411f58a43289e0eabce8bffe140fd17e9c686bfad238988f0dbc1a1bce463c08734e92334b628320954936ab76c039f838051a578e679c5244ee24527bf042dfee9c46e8b32aab07ee8be0fd7230ce88679cc93826da304d49e514a03a1be84b71910bfc369e67fae09c351e43c883547c52a511e49f4f8176530c219f78c0f0975ed51b65f9bb0b1f5b897a2de5a49a2255158ce52597a04fc64682cb0dac34456b5595e0ccb0ac5548efa3b6bd8ffb2c53cf586845ea9693ae8c9b570b57d33d03b76dd3ab6e04b95ecdb9d17e57c697eb998f64127450c47b8ed99d3e094a8cb7f2c18ac65bbed4f3fbc0c289c3ce576af49fefd57be90ea5a65c3bf28dafbf56eaf7b9d3facc9aa5e7f6e32d955b47623e4917ffade893c457e6edb30a66812bb994bee81e7c0b9f9cd677eeb14afdfa4ee4b9eff5f798bbfea7559fd557aade7e8d26ba755eeaae6aa85a3dec563c4c39a55e370fa396703ee2be5318f33316f313c6fc8cadce7cb06a96e7910995b99ff6af94fc839c5b32d8092113fd30eecbc4f8a3fd4d87aeebffeb16a5a6bdfccdd21f0e8acd57fc7c32240282f5ceaa2b8a6f5a64a08f8004b6dd4d40c20670c5bd5c401bbf9ba956217d1414fc3e73e4b2f17a237e78dcdc937bb81e5ba19f5bb81bbcbb9114f4673264278737a459e8037d3a63d3cf50b4114c9f921ddb6634fa5f8fb1d5e715954c65d21d2a890170336e2a24079fee5970224c007c1c79d8e0a9a6734090f712a5f6608e97cf3be01792838d71048d930209d724519d091b848fa0c624895cdc9738a9257362c992e211e137f3b765fefab4394d951afed880eb3ea9672e6095153616491cc489b10da4b981ecf688acca958d0de48d6546eeb1e91dd8aac3b7558b95aaf951edf2fffbbfb8f1865925553d9b1ecf2347b217e23ad3275b495756c59a7e500eae205d7b4040a9ee1798be175fd5db15076d3e52a965dffc36fcf3e95ab298f0ee9103b464372ffcd393335fd273397eeb7745501e9623a92879b9b16a909c1630dfecac405e6f046581af050212613951ff7f4ee9545772fc7dfcf4450b75ffd737c6fedfb097b5a4f2bf669b975fa7094a9786d35bb9b9f73e4e5d52bfbef2d93294cce955fd9c6489e7374718dd837270f99d26bcf8fd4e0863813f1c8fef8fe7e7bffdad5edff3664fec3717de55c40095d27c8371622fc3d70cac80a4c25e58309ec7e77adb76dbdd040403600984fa03012959e05840dd6f7c7dcbf4dff402a91b6a78d6655f4739ca4894d0c4447d7377a1d8a031ddfe403ccbf4c998c939b070e0efacca6424249a6c1cd06b701006700a499304766523a699a5ea1bed22629ca6df1d0b6f249c0562a2b10dfcb9789e8d71e6e279369e978b7152dfa8009bb2e440787a88fb7a609c36c69998a0f68117117b272551f1c5c69981e7e5457fa7fe0fce6dce051ad4f938eb39bdae572d5ff2d15a24916495155454c481913b23111096401099ce223e558a8c0016284f7373926de8f867c51a3dd3ad061dbef4262df158f7584535baa81867db9d9d43e83d0d21118c449c243910d7997e80adc46f746709c4cc73908a33c89d54d8b4365eb9a6f5142d6b7ffdef37cf78aa963ea88ef8e98e5ff4015d3ebae4fb121006962828abb17087269d3b3b2790ca10991b28f29fbde128a383cc5146df074e106404a6cc10e557e843f0d9cacfdcbfffbe7cfa9085bf2b353bedc71786eb757140a3f6dfb939e46a3fbf4fd6a13747e73dc3cd6abdd339c9644609697497e78cdcbf7e9ba1c147b69798d13dc3831fe39df4c257a3df5fa6d7fbe38591b553314ff41d48454b8419fba0e45ecc1b083d491eaca2a53437052a49db5391e814d90b33334572bb91db6ea3486e37abed84a3f2374efd4abfec1d251d877ee389e49491ad3272d61b994cf5422872f61a53f17b97d5e26e6922da93d6e2ae66c4bb1e574bdcd7d433ee6435918322f37b7104bae127fa8b08f7ea47bc9b3e229fe3e6b7bb1867f7f871aa21de1af71401cfe3c4fb6aac8923e91d8e78cff6cc4b40c4fbaa37969e30e609a5664d19f79f455035957d602067d9ad0f78adb75f3ec30b2b071b58b5c140e74640c70bb9145013a5d63db77c909bf2a4626ee9800fdac67f7facd3e7f07ddbfb22c8134720d33cdee4c8086c83ef1ae0eb9db8c6bf9eff1d8a202ffa6063c96f9a00cf787ff4214f6b82f1c569cf5ffcbc9ebf4d5dd634580f89acf41c038bc108163d6de0d62d066e419afccd389036773170d326c01a8020001b7f42ff0b40d89c36e2ef9b7ef2fece90aeef25f00f8b3da7ecf39233dd710f1df674c4adc13eb1df975bafd4e3da6cafff6c74e7f875b5ed08722728a25e6694101910f4f9b0ed08f2dee25c9119001c276cfadecc0f5b8fddf4e4efe97abd6ff8717421050652660c043af3b94a9932a89c04dc7cb9d436f5b30021693bb35592b6bb25106a1103b8e21ec111806b705d1ff46f763db4d2de99fd88524dd20e987e855e20d62bd6e7e97ac21445a6f60307c691c9e0f038b2d54402732dee4b0d3dd57caf4985c8b5b8d99bc58c8a543e14f1ae0222de6f374911d56aae5b427efe05e89be7cb08e230c63150f4fb21f2be3bc67517f07642c46a2c92dc533b9e8de532e2fd24d4148f457a2bdc9781fba865e03a85eb32709dc275a68f4340cf5f187f3792c85ddedacd7191be729c32e2dd685e11772b23e9154792f3381346bc571554dce3aa4e46f47975f9b3fa08dce26c98b7f94b7349e9c10612a75c02955631245fca75553addc032a46dafc0015709c9a48a529d08f746ae24b9af81218ddfa9e5349df6ac7ecda733deb866a9fe5baef559541239dc7c5f3dfed518ffb62390791e5912c13ca27f9cf922d65052a18a752a3309248920affcb9fcd24d1d95ca5ff7c45df7e87db7326ff147cb911eb21c84b80c11fba5eb309f3f623e3f0144a1ae22d4d62f869341515df451e7a6e439c06b808ff09224422a97530141c859a5456ed894fd9a545a22f2ba02b6abf217d03f52a93f272cfa6ecd214afdf2cc98c563c24a1df65cce92933421497d38edd7a6ae8c4d11e4f062d4fb8d723b542f829cfb5c86629b11e4b1887781bf9023f60b300e05fcd1fb7f9ef5c5d32f6a867b79b7853dff840a8a5557349fa980ef63beb09e4bb02f2a487545297b28b50fad7322201115d0f61401a166036618e035d3aa98bbafde226b1e5df244f1c94ab5a8dfa6cb2afd42358beb6e3ac3a5a40538901947a0ad804450eae746fb1d38421b8184425530b67aaa03b6a1d838f0abeb66eb4fff6cfa490309ab19a0276c05d5284813c17d34ce8818a71dedb2ea05de66dbeb662b03be726143228297345ec1a72a88bae9fe725ce4ce0177ebb53e6edcb5f321519412a40d035515a952d86d17aa167673a4c2515718489c1a07564500330ca037a3025fae2d6fedd43f46bb3680d6a5471fdff876bdc51aa71edfe91e97699205a5aa1d319d2be623037d8fd7996f9d4a95a9df6d3b8aaff2818ad3dd0aa1933e1ef6f9139a43dfb06ee5cfeb9ef3ce07ab0071c03341862e9de695e13c5c0f5514ab08bff1e223a706b66d60de59374f91d29502e23a4ec541bfcb026eef88df2960ae0a5073e0ab9e5e72f6587dce64b63eec8113f57852de4ec9744b39fbe2a1aa1b419ed49b935494c96c7dc027ca4e14e56fdce4ba3d7ff9d280538676f0ce1fbba5932a906c7bc2bb909c4868fe4875c581b211c002017d6d4f131034e62a3d5ac138481b72ad528ba7cdf86ac179fa034fedf8c57e7a81a67e9a3ee1d07a71c8329863b6a3f792d191fa647ccf85ce9ddc6e27c37ba5ba6eb6d256605bd124e09a90dc84fbbc8184c974d0d2a84d6ebc4d038c77d50cd08b2bd87416f0d4c5b8c3b8cfc2f3c2783f2bc938cdc2ce12de662ad0389e23c69923c64904561ca8c9e215bc04f5cf768b078ed207d8c8b75eb787233715a9a44a5090ab14075909d93ea84f5e57d00d13c74a070f7ba5089515415ebfe00a99f18164e3164eab5559afc782854a357cbbc5e357bb6f3c5ddd977a9d8a8f7bc930ef19e81c61e6d5efc51789f6b3b9a0543fcc8fe907474c7bf03ba32b2f2f1ea9d4d482afee7c7a88528b7e9cfefd6252fd1161a5c0331c3825703228c6fcf27c1e97b8cf368fb82cd56eab808e9e22a12bc88d14849a0fb6ef13c34a4a6a2a74f7fcdda0aa61f75452ed900ae7cad87d9bfbad9ded8e6fd3b2353d22faa438b0ef2103c28bf5d9d3227471832312326a76b4e78f5bcac055f84e89d76db5c30e0ad9abcbac2e10aa5f668f7de31dfdde4b96ce99bf6c901918db3cc82961be8022c302650daf10f3cc95362380052a49db4336106e1103c8482337267106b4107881698ee4fb4ff3163fac5fb47c76e9b3df8f4e88db8ee28ad58e367daac59d0fdd6577aa89ee84a370476b71dbb095f86a713b36f043b76cde3ab0283e6645e3e91d3f2efdef1831ce31629c63e2c7453597b9c67b6feffbc7d510878d2171edf8b871f6f68c13f3c778148fb3b71867e2f98c8dd3f4b3a846b8a8711f3ccee82a595f77e59d939e52ea93ab9ef962d0523312aa0059d6c640f23e2925ce998cb5a4022115078c88cce9d201436f28bd5108a2b1ae98d631d6b5bb8e674efdeea11583f5613b65d3f98f1a55c21c310f63f09e61e0f27c6f7d1d7d8f30aef3ce2b7f0fc627d7a917bfe3c5fffb05d3bb0ed4046f61fe9435bf8333a7fd26032c892014df23fac580d0c1930a8bbddc4679f1b1e441aaa607bdcf6548bf7716bf770ef8fb775e4878cbc5f727899309dea8d8f87f9f30fdb83ff4fa99f5d4d883ee18aee7ab8b33cd4d79c335c855e275ecfb7ec135f9e97b1a7c1151e33ce0fbd1be58f79f95ff9a3449a91f27e40f9b0a1521a9a0f8bd1ff0ce17f7854447e72c9fc3b4deb3bdbf276f7f9104c2818644db491229f0f64303f07b5f3d099f96bde94ef5aa39051b22b65207fc9255e738bd10429b5216366feec14d58c2d17b93051206b903077ac770df70e403c876b29d6eb632e27d2cdc6e3b89d41e390192830a901c689c9475b79ade66dbe0784d9f395eaadc4ef32b6b65cb88f7c40159d50e248437cc96633714cdd1339d5ff8d4f8e76fd59be3c9d247493545eea27c206084acb2a2fa1e929040f4272f1e4ee5f02ee0558074841400da06703cd340efef21f42dcda02dde7fc6cc5f6729d576ff63d79f3d59ffb63af46713f70b0749ce314ed46009f236cc467f8a74271539b8622a98e8fad87cf9bafda7efa3cfafbeefe70c5985f7874a880ef6629224b0af48a2639515b93fd3bc929b2e54246493a8b8dc8b9f5548240148ef1f48404c90a18262828eefc18ca8b85e465257d1f70367cde518c85d15df9957aaadd4b225f3bf5f7ba852ad738eeceb9e4fb546d57df75823b1627e93781f2697282378a657a2cc10f811f15ef95179cb8d1b95fae2df2f76795a334e4543370dde0aab0c49d0d20d9dbf8f9024997063fdb32a8f54b479cadb222a49fb8b09888fb3cb330089b0a31b300aa1ec71376cc9335b9ea85ca839d10bffbcf05b4d699b9fd4a676c719fa5566a5aed9bf7382a7d0464520a13eb648076d12a7076dd06411ef64cccca2003645c74904ffd2016dde2e990d82fcbdf3456a8fed0dd02b64ddb9b131b0d15d2c7419a0e7cb6924547163b9846a4f8cdbaed638830a4b753504936d510139b836ffb06ec22fe729f5e9c2e7c63eab0fbea29f374ddfbad50c8ce2059853ee6ba02420acb222b7533ae0c84d57a83ef860a2b4ed71e9dbe31b138e5cf433bdbf87f48a707eae7ac435801e909675836bb4af51b3f6a2330f8c435280d51fb3b999752675e103799ddae89be4a04d45812abf4d2f7a7fe53b9553b76ace7a5c8d8f073e3345cfd19b9b8ab7bc82f90848f7cd9cfa5cfc0e022d397a72df65151508728548d247f556e4c12f09b3efe0a27e9ee8033a825030be3ceff3e877ba8e739ae1b9cc796bbc8bbf9ef9ed2f33f5f63ee9c4abc2ba9f529cd2b9996bde962aa96405a5628c9a8d7734fb69602023e8c137e3f8efef76eb0acdbbeae73e0bc1e0708439158822b774b23d918d4fe476e3004d4a5db2c8ffde1e98b4fd5504845a9e01c4c971a0a1e8d3c68c37be6ffd76c3603797cbf2b1f3cffc5a4fd4fe9ddb4f6b7d8d52a91bd31a1e7c6d8267e52bb8e5527a73dab88263080a20923688eeb0310c807f44925adc496d1063d9ebca2cb01d0dd00b33a112a933b633402f281dfe94ed0c240c26a8b9e63e11a782036fdd0b2bce1f3f5e7fb6664f757da991de1c2f6fb9bd085e7b4c38289e000759710f4088f864ece500411190c61c31447be67ce9c001a1f26da802bc19181b3a0a9880647aff1e5aa2d48a090b3bfeae39bd8c9cc31f3a42738c29dfa674ce3cc883d360cdc0bdc99c43b24158d690d34560c474ae0b96a6ce993ef871a516749a346d16fc838880b29b33248a22230bc76c1d225e866d1aa492a29c4a24c9615e1d92348860900461a3df9bdfdddb643fa8d9de2e7b2a45c4f3d058699c873e7de730eecfc5effaefe545a5eb5c09a6ded0c68fcf3956a926630e1873c9ab985ff70bf873c7d9e8e79a3ef63d4b94017161858919d6b2fb4ad7ace9a0d46739cfddf736dc99652a1e628828ae83bf13314ce4cd86efcbaa404884acc222d5556feffc246f7bda0612d078e061f4a54d041b9c757b7480e88363cbaaf5376cb953a9af7f7b7d7aafdb35c77aceda7b5e772732a22274bfa7d9b00df44ea6834e6283c857d103dab910bafc885797bf1dbafd6ce0e92eee0b639c5e5dabe3b395085d39fa725cd9c2b621c6a96cdf389d78fc2adfeb971ed3edd2fc117ed18fe9f4b33de3b439aec43ce714e747f7205fd2744eedfc2ca586bcf5e4b12ee7557e4969334a0ee79338b07198632689438aee14e8465e56a40b26880d54253931aaa419d078dde27ab68190aa04ebcf3da88b9b6fea553a48a91f6f1fdcf08695fab719654dc68fdb06eed8f717b60c87be07e28fbc362227ecb541551e51b160cb1d4a4ddffccdb01fe0564b121707ea617ed87b4710661949ce8443d828a48ebd4ada88b2bd9079701b3022672149b3bd909f13a0d377e8bbd0381ff28e9fe6a13c2ed9e60ffb7e74d84c2d01977f5cf2c44f676cd39611463f823eed2fd3e7f5bf6d1b5fd9d8b2e3dca49f5faf7e7bc163e4464dde700fc4c6e5b6d280b204acaa123611b2f1c9f991f358fdf6574b20d4228921ab08f2d00787c91c838dbe9efaaa0595ebdcfb167d31eda9a9f594aafb75a3bb7f395f73108d1b3f78821bd1bec0ea5c3bcbf3cc0ce08a624bc0317824099fe49005afaba190689a52ea942491a8413608728bed847a1bac3a4b5a235a7036901c46727c0aa9a0308b4272c809901ca4089e2bb2c006e5e00af62e19eb1927249e67033dd20000800049444154caa3ca87ba1b66f26923af7976ad3e60af1c72f658f7ca91ce264ebb4e1b8674bc50a530c188338646fb58d7e44dc48483bc73c8ff9d4478e2446df4893050cc49508b18c01274d8db9792734813bc92f95b4a5cafa0351f2cbbed3bcdb1ef5fdaaef258cdf18756a76c6af140c267640077d8e0c6aea0dc5f6bc87622243de4e05af3e2d2b1a3f4fcfcfef2d46f669c6750920a8f732441a2209bc756a8b64a496585dfd96b8d5454940e9ceaa5d07c1600d2c12de6b7da12c68eb608609e80384f1cf1770e27a0f3260c988bbfebdf0fb832eb3e37f757bd48c3b6dddcacce4111e46cd3622fce0cf38c00491dfd8aec8affb9b68ed175deebf2689a3ec78e99f1d41f88df609514f601bba5cff3f6e93b9542526155ad34a2c3fbca2779d86a3bdbdf4402e11636806a4f578d07840e95bd2f28bf3d71a4ad0d242f91a20c7d20fdfbcb5bc7eeab0fa403078f3e671f2d994c58bbe01d3d7155232b07accc8c7b26710c4111ef170644bcdba8617ebada662deeea46bc3b594e17f42982381bf76db366368f5346bcb7445c697f6f847a825af10923de7db5e8af412df9b037925e2f3a1a97e3196740647ee59d95735c4e7c79f8b7b69f6a517b48a727b27a757175bddf1d3313077cf1b3800840db8a0379abd1faaba263007301efc6f51420380d1001826ee548b75520c2bc92ea7b50e01445e2eee046a29aea24b1502df5aa8f00c1f9961f65a04b10d79eb5aceb86054a7df7e2db9b2fefa5d4fa352b8e7a70a6be765ce5a7cbae49f010b94e6d451910bceb08dfabe2f48a6c37427bdac0af5f183e09cf072165c9830e28cc13a9a64ae877ec2bf26ea3e492151f1a58f92f406494a00c13d2bb67bb258b5dddc20670a09c5166b3719e22b8697dd0f94292ab1b883772c1ab678eeaa67f3bbaacdfa433a3fb26610479dc3e8d3e554690d33950d9a5a2b4d82d0075f382673fff4ca9a1673f7ddb9d13955a78c2d4cf0bb19e4b4cc873ccdb4d7abd615f9420854929e277caaec3f8b1ee99612209846c4f36607fff9455affd5d2410d9e88550471ad60ba584570ccd83036f12f2f776b061aa36eb491eb4e93d97822fda326dee143df16b2e583a6aa4a6f08df25a6eae5d5ba9f409355f3bf860cd096cb55a44d34147d8a869227fef0a8878efa9aec1184d2470402dee6dd43236c917a9667896157d5b2dd1a076322250f31149df097c5b4fd4aceec311efa62f22deadb7e9efe0847aa296791f964c2ec2fb7922dee3bca32ec2fdc668fe86ba0ff72170922d5634ce0ce051b82eda776654f67625855537169eeda6f11e7dfec0d00b6f6882317bf449938bdce8d8e2a94593cd2da5f06ba70d41b078898145308e93bb28110cf63a815b6f296c60954702526a121ce894a2c141ca0d07a938f88db6b751ce029258f03e9cc0330c084e922bc7e8755a5e5a3ada4de9535038337f9e269c4bface6efa8996c49aefdbfa81ba75f4fa1c5cf3b5435c770fcdc9227bf56a3c0b91ca58477db8f67cf47b6dbc66f5e73ff4556a5eebf133c693919b2295895060be8a6f01a448f25c5cf7878144402ae840fad9c02a404a5144df5eda1afe360de9cef97cb1013300c1a038b6ffbeaa82aa37dcefdca6d9d1fb86f4795173459dae5d5c964f4690d3faef09c983ec323817b6feb461c9af8d94faeaeb37521ed18469ca355f7d39493fb7b8ffe69fb69888320e842d39d4c0adc420cdf542fa7e25fbe0bec30d2c0781af4837d0976d370c4836a2016a079bb5a337eea1661b40eebe246a5af0b60941824a79c4c0d454c0470d4c433d87f4d30dac09d1ad065255d4d222e9be3533af6dd64ca943ea865b5ea245c17aa58d979fad3772e8b494468d1ac586e24b72689b842c7a81a060933517630dc78f3ace3bc6abf2e923543e03d0ef095584ed353afb8cd0d20d508948f21ccad66ac6b51d11ca89555159f0fe998bf0b970e271563c593e73fd7abde7862ca9fc5e733c13bffde2beafee556add172b6edd0486a092b2b5922449ba5be2f8c8dd561c783e9dbc4c578d03af02aa1ae6bc84ad43eacaf980dfd9063cec9e1e31209403089543da1106a6c206920e5d37adcb1ac8fd54e309a5da1d7542d7767f2a95f951c70e376a0258ebd8ba634f7d34faac309543c0b3c3e6d9e6e985f7fc7ac7f35ab298d26944d308c6c1b643d88e8a88a3c5a147d97437dd81eb288219f3cbba7472772677580ca1fa69c0ff5e8dbd3ce93be1fba588f3c44da514ae77e9afffd292579b4b8e29ffa98bf265809049294b4ed9faeb6fcd959a3f67e2ad6e4dfe9fed2ffe37f37c838f032729ee4dda38608ba11c63ec05777c62c8650828be895457e40587f54e8cf6ceaffbbfab04422d02980748bae602c00cc031dedb7c015e8bbdd7b9c9efa2504b365b2b364c2bba58a9c54533c64ed3a2e4c24953d33fd194bfc63575be993f5f2f9aaf6b2d4e75bdbbaad2fa367373f9740bbdef12262b56f02a7aa0ca5adc49dd6c65c47bb6a8a827d377e724cbbaeaf54f8fab999d386d7d6c9c1918675e140645bc537a78789b390f54ce710f9c4d9bd67ce88af4f39f9db4e103cd517ddbeeed7fbf5da5d46f23274d706d50c5f3b78c22b75b3606524a05e45422d19b75b9e455026f124ea141de2564cc953a7910204a26c77106bb9b70502bf0e225ee9374ee1671a739e2f964d4cc0324ce30434bcc2b962e700b282d7c79f2f831eef8dba84b7fd0eb719f679a5c72e0937a5dfe9036bba5cb2815eaa767c6b0cea933aeebeb5a32db327cdda68d4836c8f34e11cba433271d3ba57ea182437410891421aca2c230399ec29613b297b488b7cb2c19be1f7d4797d014b69f7dc9a61795ea58e7f4f3720bf48fedd40375bac6f65fc9595bef9bac25d0df474c1bdc5f9f2f5ffcf6e2b9eef42c1b38ffee15a4faa3c03fcae54569efc93984e26bc0301161a78c00e49e5b2ee23b2a64ca161161ee0b8c2d48381bdbd1feee12886c1103e23f6814e2779248429048524e319038bd347cb0741c3c35e07e980e512f1d1c60da63dedfd3c66b1cb7a53f525373846daee8d4b1dd4aa59a6f6d5d7292e66c6bf5ae5bd1467368e967d6ce3d584b2e2993537aed333d36aa6a4b0e739062b22724073b201ea08f90246cafe42025891d4d0f5f59a762999b5caf7c63c9d9cbaf576a73cd75bfcc7b4d6fa06eb38e9a3849138c777e3e72d122b75a5fc585c499929fbf2f771179d151d237923c90f48db2e6b22421385ff23e61ef128a3778d00b2b4d3a4acef2bcc70847508b18c0ebf566035390543024d667eaa906b2e44ceb1212740d482ae990506a6e56aad5c8c31ecc385ac38687f4f9b726dcb5ebd5df98b55aa95187bcdae83170d0243190ff3f49763eef35106e8eb301072c250ff66e0c1b1058437b2f6b7c9ea0cf1a0e30daa9a719983e41a92b3eed3bb34f58cfc5a4cacb5c82baa4e79cab7fd0d78f3b20ff8e25b061d1f723092605f888a160db2e24058ec711927711050eca887eec2319cfe4abef21bc0b77ddf7dadb0808b5880124724a5581057745df02000746aaaef4cf0de40dfb98b7cff0746f5f6ef45470c6295a826970e2bee3ea7753aad1c21637367e45e33ca3d6e3759ed6b071cdc1aecd25f5fbf4776b3ea52f1e6ff572c76b7550b746399d4354dba859f432abab7551ec552963b16e207fea32ef64982bace1dc37ff759f32cba8b3155d8ed665e63e67ae7393bb80ca37960e71dd5dcb528abbbbbaefd2014583dc0364cdf5cb2e5ff789521b5baecad82a74da94fe9923834564af8f7090682e52d33001211d3b1112e2a888609ce8859cb2a2b3173fe73a42dd0e075e447f19e1902d6200a9b6422028ccf08090f03ac5fa4c23c687080741acbb1ab0f1a4c3af3f158c133150d4e8fbc814179cda0384830f2c541094f3cd1c2d4920d20d746f6fb601fc9d08d2f7014c032171558c513801f04903ebd4c175743ee07b90ea9d244e522d717c0649e8c438a14fce419260f07d54d783548b58f755c22964d713fabd9580508b182009090770914e9308c9615e980aa3136f5810102610c419c21b2c6dbcb89e16c8a780500d50adec9493bdcf67db4d8e183771a8648cede07bd33ddb8840d8807410531d1778b3c46735755ba5486227e377e401560e6f114ea34e816de5debe8c33e09c5522c29973fc8401ff6ac2211b9531803157ae4f863f1ac89209ad37b10e99a010a7fb88170fad2b960c313fe542d7cec91331efacc292849a525e8481f71f2279700b1bc03657fcecfb2ec4809e2e20be43ad5ab88e248f142f5e22bc559280906a8b54b4987fb271c81c60fc5dc8c64784ddf1becfeeb34da5ee6a847bb8850d70002deadb06b20a031bd5c142a882c4e0c0cba10a1fb8121f9c3e7c05e627053ac854b88fb24a8c080844fe14480129901a52f03b4b4404a9c200f02ae0b5268b7e8edaa38d0f5c8ccbc1387cb98928fd33057ade893ede9b0f7ae26045c05605d5c87e0f7d72b3edec85952778f155e17747a8529c30a074c70d277ccdbfaed1b84c121d5515419fd627cd33b95b82e1a0f5c9f34db5ac6104a7832705de3accb0a02f8da7155059955344f9d180142f83038c395a1c74be38193bc13beecd2d6200c789d0814f8498246e3a1fb01e2d48060ae7818244920a15217f0fc22308884c1e4b92067de732b87f57e2fb5491c41110b0b9fb0907b5bd5d02912d6c803701b38a25b9830eda221db4e0fc885320af2e3af049224911a26c2a9449a4db4cbd15fd1f12e36742421208cdff58316e15f01ebbba450ce085269a2f8218aa21592783d36dcbfa0d32bbb2c87e5b3113f0bfdeeb181f491a528516c469ed2d075bd800e9ad25555c969464c9b607c2429c700a189a1470c8b46e99e31591d8940edd2721922e9e0e2a996c0fe3fec7491eb2850d604984f62bbe0b7d8f14712e30630915177d0fb68111a3400484f60b7d0f620cc43e621522ed071167238de37bce1b6e6f9740648b18c0eb1b134c924915fcf45955441f000739492895d8a02910f52b2142a6c08d2e04513f85206d6c10a0907033e603812412aac468893ec511900d049ca1daa2764f23fc22e7933c881d3c9fbc6d48b75a0509c58db78942704a7cf0904a8b36c828f13b119883c47d64fcc30672285755588c8fc6bbb7e9e2230638610359720624826991bb2511568af8a66478a8049882f52955a5167e575049b16e1c2a2b2e814a121d491cf83bcfab7003dd6be679475bc4009644b07fc98b939d08305f0adfc3c139e040b2e3ef019b8682ad89093a9c45f87b200ea70ae70a13187c47a74a3c5fdaf8a497d56e6fff3402225bd800aaf5ab1090a668e32020870eee2a3ad049e70ee36e08128b850867f2e70f81530b216297bc6bacb3c47d504d8540182c04c4b1044204060190aa55d237db3ded2a2f245520135ad88eaa28e00a91d75517a08f886cb6912010902280abe0865d05c25c85646f74305204b783bfb304d45d8c8772544112dadbe20eb8450ce0f5490736a93a6c40bca745019158375520ec15f062e3f586804cb6a521a2994a94b21304d9b41aa28fefc811fa34aede025fbeb76fd1efddd5ded9f03e5c039c20924a2a042ad33aacc2fb32e389b80e0bb63c5215f2bc50013cda0fcf7a9f47dfc181130947f45366030a80a5d2ca14584deb251cfc6abbb7fdd3090835923810c8c6120a1d40c268cc111644f1b1404254a43e823eb295b24a0cbae310227759f4c586b6f6f1f65975015b8005dd342db4bfac8150d2c1c32a2c44ca3acb00893382379583dad3cc61e1c0639d3e7170c4e92215066f20da50b6f7b9ccf1ae12e39c539d97d90b1abd876d00af4ffa0f312f746054e180b3d60082f072f4f379e2394845e280602892ec40c09930930414c1dfc1f8d07ae7030b0c183340bb5be5ba9b9a430cdd50f13b1110aa4bd453dc88f7ad0aa3ff27fab061f077682beea3752f55502471df0848eb9fbe3fe2d75456c2d7f80bda3fcd06b2b32d62007f781b7dd2855adebf87a81f4a7c1dd93aa48d435ec73a57e2ec68c1ee6123ba6cbe5c4680b2029f34daf1df49f5618bdf855717a5a2f1d95c8274bb76c038edc057f967b48801bc2e88e3c7c1266d68bcaee43a0a27c61bf8f7b0c06f0bbcd4efa312b748c038f65093ebd4f777a9b2a5835dda12e8ba1cef7581f31b09788e7cbe7c0e8d23c9b8fffaf6ff8b0492acd906c885604963b72d206d1821babb3aed86afeeb74fe854a58e79ec8cad75ce56aac9432d3bee73ae52b50bebdd55e75a4d5c5aa62c8e1ad95e77d2d4f59a6b79d3f9dc72259d03f4fd86e3eb15e55c56eb63d88ec30d4700759b35573c759ea77bba7a31faeb8b94e1c7fcdd5ac8d79bfbc9b1e0e618e668ffead0b7ee73ad5be80a15e59cac2f4365d1837d95bacf95204a5a16854ade556a43fecabe9bef506af2daaf9f7253962cf978eebc0a18731dd8867c2534c92b8e6c1e82c028499068e30a6f1696182defef7bad6a2ba8850d600905ebce92bf538b00ca830bd7cb1441ded05215637c88513a3576dff1cf743ba2865e59077538eccb7afb2a556765fdd13517b96aafaab91e4276b1732dd5d97055b34e4b6768743ddfa6c0675bd138796b8142bcbc65e4dc5e588737a1aff8efbfc5bf8a55687e2fdfafec4cd7bd7bc584df5fdbfca552e353beb8329a2961e1daf57c109fe69d176654e81c0474e065c5eb16467207c673ae8d4ff3d4c7fb3bafdf20afa8b04ad898c0fce5aaa9eab6ff5f2510da7824b286016dfc2e378e15fbfd3ceb9661753541c8fad709bf759dacd75c4afab747eb051bea9ff2d8e1b7ea6bda85de6ef387eebf199ad8c20d5cb454dfa85153e696c253e372e750295b332a99bb4a449cc7e1c3a8ab9d0bcb06be1ce08b005f0ef045043e1bbd20fed2db7e503fb85e3d55af55951716ba2e8f95df2db84ca9d29e45ddbed71bf9f73b674e1b79b75279231ece5f4a2a32d2bd1361116ea7acfaa2be9080b84fa27d77efdffffe1b71275b18d03680d76f90244d90eed7fd6b073e795c132d11b6fcad4df7cbf4ba0df54abdaffd0d1a8e0f75683b58c39b42b96d96b96a1c6b79e368a4bf35c60d70d4abc53c2556d1b20f9e6146c5b9d7c4bab2d1ef233224d8de0a7efa5f83bf8fafefc527332e387a5968c6c4395b9db3e5680d5fad4a29cc74d54b1583172c50aae2ea8aeb16bca9d4cae282db3fdfa8d41ba3ee9ee7964c2e1eb7e54d760f172a26b91e7deb8f246e257ecff6e2f349d461b597b6ffdf0808057291712b82be543de925fadf55cfddbaef6b4a35bd63ff79975ca209c592d48fcf9be94a25a1f1c70c77f977ab221a21dc412e6c2f7f973449219a950fdfb08b387715369e0f9f02be08f07937640ef7e7603c1d802f022c1e3e3330d58a4c918292b51a5ff5084950d31bdbe5b02a4696771fa30ffa0d9fad9efdde337a037f78d7a4e123945a73c31fe754483752f2d6a20d4c8183bd459f8cbfa4331692c83f4e32b10d88cbf86afac4f044445fc3bbde7cf78dc30ed392f0c6fa4f5caa097b4af394a74fd39cb9f57ba8c6a1435d75acd5075e5c8610f8bf7bd8e016a97682d6ab95842149ca580510a25dc5f0a039eb9c27d7eaf7aff8b1ecc2715a02d9dc6ebdfd4547a53ebff895ab467dadd4ac93c73d568cf828197f210b8871802b412240d2fddc06c41bec7debf39f4e40c206f0d224c98308c9c54ad56dd3e04bd76ffee606afdc75c64f4aa57d5ef38a1b87e88d7549e8a6d3ddc8f453acb1513f7b5ae8b69018628423d9c11fc67d3646b3472486c05c5882d3f3718e010470473768b2567955e569f335c15e75d992268fe979eff7758f15a3e00ee9cbf143fef244382820eb65031d383b54495d7618fdbd5d32891840465d5ecf7184e2922beefdb46e5da55abf78e491572f8d265d2cca6da599a3f3436f1cea26b16482c0c93e693d58e887d10f627c4cdf7fd01b7cb1c264169ee2c1c77d99955ae480f311b01dcd26bd83cdc972c66efa424bd02d8b370fbb5da9826b66a5bf71b9667826ddfdf81ca485e7754801b314f84a714b24d190242d55b6c2b6e7b3e94576e60d7667fba712908801be1427cd946a92d3b224454b14d77ef2d4c8f3ffa509c62b356add73affe5be75051c78edba12aa2e4871d5073dcc6c1df67070ffe7c98d02fe23a1c11735da0c460035fe2833f1f7fbf88379e8dbf6e2f2769eecb0781bc08efb98b3668502bbfacece1896728b5f8fa5f8f7f3455a9d786ddf1d464533d3d963c6eb4e8534022a9c468a312874884c3c6efb451c3bb7efcbbb4850d905e4e1679611da2d4559ff57dbc4103a50e98d86ed04d599a607c98fae9ad6ee5bcabad798d676d839190ebcbf2fa545583f1d9397cbc7eab8dbfba8484f027dc6f3bdc5cd5983ef8cb524be67eadcf8d82b1b39bbd709e5e9f9fde71e1346495e688fe208687080af5a5ad4f12149f71ebefd252feea01eca21636804b8912cc34d05549ddf29ffedf645eadd48925e71dffec417a832d4febf7886b2cfbb7b5a079f3b8859821544516a735370b310f7fa1c24d362c297d50f64a9686f5951a1584240fcfedaaea98ebf0774b6c1c2a8599419c19927767066ca0ae286d4b7d4b96c6c5719421383fcc597464f1e3eecaf8bbe33d88c02acfbc64c630ec4c4bf9352567ff2b946a5cd062f9a5f3943a36e5ac4eee86fab1eba7fb4cd31cb433c35948df990237991050c1201a4944f40bc4ef79e2f7825df106bba0d906706967eaebf768f8e4bea342b728d5ebcbb786e4dea954a3b1cd6b7d76ae9e8bd2948e679fad5c9373ddda37c57d97d8411cc5a2bf5e0f6033fd08fa19fcdd33cc7d62fd5329d70c71d05b027f21f0c54a387bf031639519b0bf72846a3693f1e761fc1918ffb6c71b542f6747d7a9e56ae5f4fa74529bb63e4dafcf035ad4bee24da5b29b77ef79f0294a8d9ef9e19bdf2070308400d910dcf42939236708a09185f1bb0d18f1fe9dbf3faefbdbaccfbd9e80840d084c09a1e11d33dfbdafb3e654eb5cdfe0eee1ada21b605ce793a20bc9f0b3969018620b3d8267781762064b20c6d9f622e6e423c0e73df8f37c12430f8cd13c9708d61cfcbd13fe4ea27b266d742131f410124321e333ef910fefabaee63d59b2caf4a9206ce0cbf08cbb5010c07cd411e96af5c3dd1909e7656737a86c6e253e8db9e69175da9cd852a9cef75e30a8ed754a2dfa78e6033f0c526ac386d55f539d0acae1c592751e600ee3327fcef3f6a5fbe45f5e492f62001f1c790684f44a68f7c1b193dc142657edd337edf5e7dc3203a9a7f72ed07f6c667d56c7b576c56ae0dbd19b32a85e4c1023216aec5b98bd0ca1eacc14eb97189f1c5ccf12297f77c2efc5470c490fb91f02c6dbc3871ffd80751a63d4c47859f58afd45e3e78af63bd6ac284e95ba5f7a797b2df9e5fcef92ff1e778f52f54e6e3479da614acd1b3671e566646ab010c82cbd3bb9767e2efa79e8033221e983df6dc0c84e8d7c17b4d05f3d801d6c949204594de9bc706d19b73df2c6191d224add97f9e1d0f73fd007cf05b53ff9de55750c745e77bda29c5ecad41e478deeb85ae261f33b6a18a3c6b4fe48a6e6346a8aab21a8817c3a6aa2f752de5ae8ed4d9f6b8ca346b5ea8d38d608d730bf49e0cbc275a8796daee71ae543ccf50ed76a1735d01df47be33dbaa3e42ee313b5cb8770adf230f0f5f68cdbc17b50adedee2a2b1ebf9e97dede7911f340b5d667735cef2e69b5dfadfbfad95395ea79cc8ba3bfd51cf74dfd5f38edac2bf137e41eaa81ca93e95f1898b6dec054144c0a217b72086e99e4c0cca49502fbf6df9523df46cbf23e979d3a9a29d5e681a36e4bd59cedddbf0ebaf1c2214a5d70e8ed874cd5479e7556e8f91e4be2d703d5e446dfc1fa89d5d837eb275663ff265c87f5c9b5ec69bd9aef68cb9adf8caf3fae33d747047ec2d75eaca3a0f112fe64e395fb4baed370d078057e1bfbaf373b39ef92759a3ebf66a9cbb076ce38effed18d94ead3e1d3d7fbeaef9873f1251f1c8075596ba28135871958a38b81692d0d4c81a332650de7dc667806c78bd13afdcb020bf73209842936118eba0686f446baabf3c0963d0af4c7685efbae2f57eabfadb5aa5c6f1375b6becd3d286e47edf02755cde84d61d82ea68063a2f4003670f7e1eac6d1bfe88f66fa5df1f96e578703df6ce03335c5fb015327d442b7717d0c5f07e0335503baa27f3bfa7d703dd556ef072f2aa8b814d56a1fc9e30e47fb11f4495ee9ae4c65e5662cf866e2b961e0234e54011fbd6d27e06b0a7c9d80af03f0d14c29efbc900a0ff78fc47bc4f0992765ee24c787163a2074627d2d8934fa7ebfaa73de53aac1a9cd668fd75f76f6e4f1456bb04e426464a6f5b22f6e46640c4b1a1429938b3ebd214936f9bb62c4095a18cf856d87eac0b892c6058d6fcfa8a3bfd0491f759f32448f2ff58dd49ef7df161d5b8b669ae0591fd17a404dee91b09da146b75ec7a8814f5e785091d27aea84fb6df45932c177cba4f5eaabf94df88a701df934d6c175a6df83d79b771d058cd742cd7e9564bc8c8ff717fa7d766cbc711611acd35d23415b2badba692ddc9a2db59a1c75a6526df38f742e7d4da903b6b6fdcf2f8d959aee7c3ff44f387db0aa8b522b916deb1903391b32358a8807c9f3852314ecccc8b7a7ed25048408076f383a2034a776d71b03e7dfad45c69473d256bfb0c188e42197f796222de9fc5192551f70fd8035c35c87855318647b80086c4304865fbaa6fe51c1d29ae253e598bff7205d3089f401b6873e166aabab6812ee043699305e7eac075f4c34cff08c7b2497ae9d82f708c7bf07eb8c7d3699009df94861dc97aa03a9ea504215219d120a770d2189aab8f4939a3cdb6245a69eb9d1151fce1b0e0e8f0f875cc0020302dd7bdf15b8a9985707effd3bddc20648d5ab9bb9e0aafe8f0c6c74817eadfa873c3a7cb3be666668f529efab7895615ef4e22c43f6f4d73d241e2b3312f4bda5b139f6fd73cd75acea01fe242a2e52a15a02bf5c5f36f0fb55509909c72b55b201ebdfa95fd5c4ad1d5ef665c95b6b3421dd7adba6d396680e7d53ceda110bde50aa746151e3959a23af9c59317bcb1dfafa6b9c196e6126eb736b7ff7bcb06aa70c4cff207a86e446d747d88c6fb7a9b8d0ace3ad9a35ced0f4f2f203569ca319df36fd8f7c60712ba5263f3beaad82025c43e75c8617fab265cb759a8bfb07a21f062cd8f9716fbb59bbfb013bd96c037c711a2ee1683af0bc871f76a58fd4c60f3d1ce5b448b318c1bfa69fc307bf39e8fbf8bc3f22789ab91eb6072b99df3b0e7e2b76f00fc558c39e5163215a7d026c0ffeb88d2077601bff9a71260ba4ea6e3849cd9d780f7ee115e6ccaabaccdd90eb87fe79c8cc864aadbdffcfe68bae526acda0a5c3ff68add4ea17ffe8b57a8de6a41eaaf9a4ab02aa734b83a1b58f566affd7db4e3ee86a7d70dfd8b2fdbf062bb54fc3c60ddbb5d3dfa379ca996ec9d5a4de31dde1b63c5446d4ef5c5b76c182579fd1b2e673adaefbf89dc5e637aeb8478593088a8a87be825522f7d04e7bc3000fbf71c4009770fcdfd17d521bbea454cb21ad7f1ddd595ff366e8f9c30e57c1713a63b15ec25c02d936d761ddc6d6b19721925e81e85b7d183fed8b6daed7eac61559b140432f0321f1c7dc7573dcacb745ef6f6a5ea80fc4e55f2e7a69b2e6c47f7de98733a6d6536aca41dfdc5290a7bfc5ad55abd84d5606f8496fa6480c663cd861647d2d9b1fd7bbdb7f0e5fa754bb538efefc0c2db9d679b941fdb6cbf5b778c03a3e5a386a17bb03fbda58d5d775fb5d7cc3ac7e776e51eae5336f3eea8b4de64fa5a2a433ad5b99769f0b49492fae3de65df87725206103a4ea216a146ff2ced737acd422fd41e9435efe4599051de524e48296073f1f5c66830c95077000a71cecf76e8e83ee4680d4ff7a321225c087bf061efc7410903b305ae28da982dc13e5b8c5bc946e28deb24673d4f3ea4c0c0dd784e0fbe683bff9596fa0d5d72f7d6333158612f53d387d3b6a8d5396504a6fedb6167d5bd7ab7b8e52e7bcf2df3f4f3f5da956cb3bac38ab9652e9e7d6287439eaa407e02edaa0ce994e5d371071d8b503be385faf8fb1e3f31f5908555409d2c9134129439c0913124adf4f8404f1249c057567736e897202ae31f5dc26b74c724b1db71b74ecac51c7baf310fae9c48a040c90747725c9776e124662bbddc1b7bdbeaa1b572423c683189f8ac165cf6dbc4da985d7ce58f055b152931e1ff1cdc4a795fa6df5d4f6ab90ec4406e8518132ae8f416eda14f7438444e654132d9e31dd2f2da37bdd7e4a759df7df534f0e6909e19e8ebf5ca8bf7bdaf1351a377a396e3e6cf1fe3bd99cb39c7a6e05ced923279c7ce3c74abd73fb031b23f81b5522a4daf55cd256961afecb08c9df558595678075b58121bdb16ebbf9cd87ceeba53fe8313526bcfd968abaf5b97f67cec812aaa23c293140273b4091c410d589c689dede833f99aa882410c6b773aa22bd308d57978c1cdf5e5591e58d1c77d63ac32af5425bb4f59716233447fd66e3bbafed7fb752d3fb8c3ee237bd708bbedc34b518151a99c381f1984bcca25f8eaaec1528454b2537ddeb378f5957563c52a9a95bbf7d7c96e6a826ffe7ebefbed2a4b0ed9d47ffeaa67ea997d6e08ab6e3310f99712a8e4ce1d5b593eec0d642abcc5561367ffee04f9b0cd704e48921bf4532ccdf9c568057011600ca248f74e05056541c48568f1d1991f2d999dcecb919a587eeefd68fc97eb1fb231fd5d0bffdc76a71da872ace6b891816cc03ab8cb08e07324364bebf543d92043250ee0be0cf11f8c672df327d1fe1b0d1033ee10e2cc7db83fbe6793d0cbeaaa72af34a4a94fafd8c19ab877da1d4bbff7d70547f2d234fbef8ab4db3f58e5c5bb4a2ffe697cc83b9c4eb5b80587f65afa30fa373199548461d8d72147a2ba3f5faa0171fc337013521da52b5614e895eafd35f1a3d7cde7e9a905df8d58523f4789a576436700309eb7769bae4e0befa2cda907242ad1be3e62373e70889b5c02a73d741d34ff77ff5d4a57a9fdcd430ebe71b949afbddcf43d7ac35d7500550525d39229e890904fd9e011801cc15fd5dd6fe6e1248c400aee075b35237747b3ebfcd377a6237363a61d299fac7bbadd16e52c26d04fc4989c136d7414240dc86255545317c36ee4ec68199fbbb5b9068a80c545289c106be3eb8cef31ebe1c41313ffd3e786ed833ee0055515593aacfcaba2935eadc7787f4bb47a909977d3e7c3e361e979a254e9b2ad1d1ef540f850a3f550a48e9d9856e96393a8c9c0b6dfda8d48513ee687d8216cd8f59dae53f7777d2bf2d4d9d58bb9f0a5425ee74c4fb18157109c1f7bd06e75ead8fb8e127bf9e311df51a88a32b46019f12a4d12f433d06aa155e81b4e795548f4170b6d59644220690249d728896a47f7a77c8bd5a024a599f7afc238f6c53d20d9b5f452068966138b4bc9a4cf235f8aa8d9fefc377f1ae2f9f4a96f0fb23c84dbf8feeeb795bfee7c21a63341c76efab5b3f5daffb072e6cbcfe7083992bf15124b7286d2cd723d50ce7f54b017bb2467eb28c0311037c9549e3d66d14ea03bec109cd9ad49ea8d4d5573e3ae1cac54ab5dcd26659f7598a3520bb4a82aea85f3ee68f3fb424b2f48153bacf566a9e3de9df2b5698bf95922a966aa6a3e473b9a8f4292b17d2fbeffa54297f17021236800f20fdff13979edf387d9852c7adec963e417314d69fd6931d37051f983e559114356163d0c73d490c73e39f99f4e0f7e3b381af0ff04580af7a07bf24803652a3f44132c5edddf842b73de3a631cdf2ee52ea93c6cfdd3b1aaa18b92159c280ae953938ba4e88ca95e00cf94015aa81f8f89b28c406e492c07a639ef5cd75271fae0f9070db8b173ea32593d0d050abf474153bb0923306dbd5b65ebfe9a969cf2af550dd6e5fdd081b4411fc758aef01446d71d2359752adf0190656a07ec3769776b50de075ad19a2ff1df97a8dec0b94aa19aab5e05b577576b26523550e1152dcc5eb2c12fd5dda32068070f4c43af6ad273ee83df892aab8c2162490c07d66630e128e57e29f7ac2b757bff186261ca7f55f376e9cb9900e7c5e8fb40e2149706df072efdfe977b20d708964590a99321088e49c7c70d29b813521776e82b2c22895aaa512c22ebca2cb83a373f4fd879f9c73c15dc7e87b4f0dadaf556bd71192ad6f6dec3646afaf87e69cbbe946d42d625b1e6c24bc4e69de683ea87225a9fe0252faec7cfb9ba8b0d8cfc136c03d80ce2feca52ef9440ff1fd94e76f724bae5ae200cef32de88ce8ef41816d8510e46c480c0385aa282f89c420039cc83bc5a72a403f2f89c4205566851489ee8bf40e1b7c811c690ef045c7bdbed39fb9bf36d21ccca2fb8ffad02deeff917ab13cddcc2b198bcbc169978283296d6e600912c2970212675e8af8891294462dbd1678a02220dd6c192a0c92caabe20a402ac1aa39a30583a62d5ef9b352878ee8bcb4566da5eaded1b0ede1876f635ee43c14729855a6aa464b9f5aa37373fd9e15b795678ed7846cf107bf46d6a1146c15545a6484ad5a642097ee251b086ac13b19401a01b4459f9a19b92710f09c277afe5a477fd97d7bb71a35da55c9acb316357851c5af337a2fb96e131ff4d99040a6601dcb08f2c21d8c201f8bb7f207d6e6e19dcdfd03b71d41be6ac592d1131e53eafd5bfb8efd0405ca985090ea098480243eb249955c6a2011f492fd005f33b018925ce9ebdeeb48b55586380a7696c0f398415ae01d47051dc02875c00c962050f112f82fbffff0de6237a5c980e2d77f7a422fc68f0f7dc7cdca9d7246ea0d510dc94e7a19a61f59f3d24c4dca67341d73d5fb7add6efd65e3c072a8dc58d5da4af4096600c2898409461e60c1ce8c2cbefdd504c436c08224c4a947b42879e2fee79dfb8a1bc179acbafe40d7b81b5be019d18b3244aa0d69632814077f3efce357b3ea2a027c7400dbc0670881d4394b5b493e0efad56a35aeeb0e7c99786ed8e0f3b93ddac0e77d8f58a4f714e033f7c7085806f0e5019fe760a9a85976ece62395fae0fc479feba739fb4d83d7debc152572cb5a0362a3968280d0c62cc5c62cc1062e25633371e42030c4f1947d0e482234085305e99c4972a11c5504e3921f6e18b47aeba29a9a839b179e79be6b343e3e5437bdad4ae40e6ae62933e080ada6ada466699d92f5d395faf9cbe1c3676ec43840302a1188286bb257de803e15bea20d2b39b93cf130f4793deb1575d629d72fb84413e6d0b89443aecc56c111d362ddb2243110fa8230f74d1c43f700062876d0db1815182069cba075c6712079e87b18131e6fe1b619acdf3bcd48fd5c33046f1f73ffddefbb9cfbbbaa8a0f6c405a37ec6d4484830806312eb42e014bc1c0903344d97c014108ca6003619b1d313242455bf196f89d246d6133a93c0050a8ca5cdb44e1cb733e5fffa9668cde9fb6efb7fabee346749d77c5026518da4cb5d336bdd677776ce1aa84c7f7fbfc9529887be375482a557272c13a261b1fdb4cc2e2f70cc0c88e8c28befd5591e8941597bc5222068634cf7ecb3bafaebee61cdd39441d7ae227d1c931db35e2845de0b447e4e810f4c3c647c6b91011d14191b8dd9d6b70dd71c087c8718af4c6f5b148effe5e7c88aced8dc86fc493687ca79bebccf5848fc6ed0445bc3b1cf11e06be2ef1f835368a1c0f035f6fe0a37930be4139ceab6e65bfc8531f7dfaca10a59655fd36721d365cd9930612612846a9dc22d468dfbad5c0cd58685bde411f46bb2dc3011168b7159ce1d677bdf713a1da32d97bfd162cf42d5bfdf8e776fdf9a56573f4c61b3cf5babeb7e81f5f71aadcc0285f44bdcd11efd17e60c4fb52fdbf6db4fdfe9571f0197a83d568576b582dc477d4a801888324fd7103d31e3530a591811c094c56ae382faa68a38262367e27abc4214a9ddae4caffd63c4ae3b825f58ffb3b2ace701018312dd6adb20322b29109212ee3c185b8cfec83ee02ff106f4436e3ef2ff1f3bef0e08bed0bef3eab6a52f953e5794acd6c1ab9e25dfd5ddfefdab7db276ea4ff494e791924d3122419245521af3fac9bcd38f868dd31440a90cd20f4bc4eefc2fd19c057e4c55bdc03f019ef7319c206567437200ee6a25c2fdead5827bc9eef0c1eef9203e70efb73b452f35e987865ef889ea78bab3e2b3d28b65f7734e27ddf9456196eaeb32bda3f38258cdf6ae3b9357f3790322ea483b14b23953145b2938d87322e5060ec4ed7b0ffab24102ad94a91e4fa052f19727faba65b94aadfbfe9db23dc83a797ba3bfd9aa8aed71b28950f01ac2b07ce450f6e6b2422519b627a6c4496f6c176ce52e746fb03ac6bcc7588d4a52cb85d832265a122202fae3ee03bb3a0721a600e7e7dd56a8ccf5c5f2802b2a67823c735be02e0cb00be289f630dc5676d2a22c70bf1dea4aa9b622270d71cf3c7d953f2941a3af4d99787c36ba87c8281a53f195832c8c06214f72fc6bc17a3c6753172f41443075cbacc40524995d507bcc340e6d848558583b61235b82b7f01444d743676fe6c60552dc0364a4d2b1cfde6224d584e9a77fe39c7acd28b7f6cfa99fbbb78fb307f5f807930f31414f17e9c8a92376b0d6f0f0fc797b23c35a59eded035fad61ee79efff35e9af8c3f20f310e4818aca280a4547996b7cf7121385898a32386080717b99f87862a754ef39e993df503439d530a2e7b38ba5e282ec7acb37e14318d754a190d060644785304f9ed58c773185f7fdc47fbc01b91ddd51b91cdf89bfaf09bbfe71b7c7add25de174d745f73c0d30b472f786ba652c3faf69f301611d5a412225512312ec590208a0ff1fe5e04425c82f92b012b504292c5fb80b42ec90b0b35ded9f9e348032bc138f13a942a28591e0011e19535c5fd483d52b9c97b3d49a695641b834dd075739fb6e9bb977ed7077cd32d07b499afc7bb5f8dccbbbbb859a2af52ff87837cbb22dead19d6b2d0251a5fc3fd5b1ca925e79fbf1f71f5679ad1297bbcf8d5ca2fcd35ce99804f611c2499d40624f7deb3bcd0ba7b5b4fae4edbd304c43680371a168e1bca9fd3e3f2c9f71c1755651c78ca23d183c190194add413add0c615c1ce8335a1bec8542053505a276368c7f6b025505f4414d9f5450854205350509304817bd06c748863062c6540819c097077c5eddf6148e1cef67ded7abe28a534944802fda9fdce2ab8f3fd01c73c1c8598bc95b83dc134bf17dc958cc711001360ef23b972a804a703a643cafc2c265ff7bf27e81ce9503bbe877481eec3e4b07af79b368ca86c337872fafa3dfbc5eed866961330f799887c4aa14a9fa198803b829ab6acc3cc90dda4ebdb55a4b6a135f1ab1744643f17e7440e0e0280701a434f1bef78384c549ee32d01fa8d4c92bfe2fada626e8cd171c74f4604dd0adc5eae87a87a96da83aa5bbae2fc27b2cae33fd42a4e6b0814faab8f2808fddd871ff40815fd812797d06a9b8b02ffef8e8b795df2ed082cd374fbf341c3c35db384855059569111815b661d07aa4f507e330a9b0c81b8e6d16a42225a3bb5425617d914a92fa52e5e88364337857dc87dfd918bfd8db27b75a5621d1df81d73dd77eadfcf197657a5f1e9a7ed2bdeedfebdedaf0944ecd12a8d6e97b2649f1136a98b2c1adefd2b269ebc6abb5a435a5ff372fcdc7bef515b27a578c5fb8fffa9c3f720123db1a41c2516def0d3bd9c280b601aeede3d497af3aa3f624371a37e5b29b5ca138623e2f275b8b18ef662dda9bbbc7c0dbd9367d279b974314ab1619b3715dc4dccff8cc53f3595560fa6370bd6dae8fe1431f2a288daf37f099e75e88b0b07c88fa0e9e3706d793ea25dba1b71e037cdef788e1ebeee93bf8fb185c6fe37ee0734ead3add354a4fedf1ed01bf81d3abc482218e8c3620e998894094d2c6a5dfb171c9b8eef3d612de32e4e5213939f93b491ed2ab860e84b236b1f1fcba6cdccddf552498976cef3cd0f7d5f360e33aeff795f3dcdbeb6c5cefcc065f1e88832295bcc4c8bb06de3629a700c2d84e2a00cea23a36004600f5baee70c8095d2f7725b886aaa2c5e5d1f119956304ebcae175dadbfb5ebcce8cea13aa4e5a574e2cd9a7c127d76d84d7ad07bfde2f89f187197f18f7d9e87bf1017fc594b2269b6f57ead3675ff8231f9204af0f923c28821a360e22144c384812811b7531181bf682fbda8b870908d924681d3ee4855501859c92c14a799face3216c22bcafc896739f78dfb880d5813d7b5ff4ae66982a9cf26e2baef79f3b4ed877ee6cb3658ce890eea68fb736841ea8010d433a9c64d2a07948850a96d633953be0e4a116908505dceeb6a70848d8005f1a63bdf1da743ceafa735c9bc7bdce870dce8beafa23d13fe6fb0e608f0d20688113e1f06dc87cb66d40c5e1fd8071f8e8b944383c07121f6844382ef4967d71c2b81e3afc0404d06bcba071e78300127e98be9cb0d7564207e6d6a337375db244a9cd75d6e6916e970f6e3ab0c9ed91bca428ce81bcb1be155046b88a8d042d79cc2d50787f70c4bae0882a094a82029597bb2147b77d7fd992abf53d7f547de21e5071071de6218031c8e6f502428e79a20d2a0ed89a7dea3ed3021216b969b2dbe629dedf69e35962e3791dab63d00ac5ae0bdd9c72e19557c6addf7cb34e785df9d6b3785fff3af0ae2b1bf87a07ae5bef3aeb2df03b9230739ff685171ff0ff366cdac5c38e526ae3b9ab3f2a426024ad17f6c6c3fa222f3f22204438a43b2a7b61915306b9ef0232c1a0f588a3d657bb5c014a092309a4efc7c668405eb7a2e2a06f9f4982124710d7fcf78f8e9bf47a5e7ad2dcfb5f7831363a870877f0f7c3f7f7b6f4949a8bf6d71272b78b6efcace306fc06c291960638de406688683d932d4f9ec339de79a87edbc30484250f827ae02975d39a5deeaa4ae860204e2996fedccb710651ee086f98ea490cd9019c1d6df8884f6290f8ba039f314afa2506410069dc011c1e73a8c0cf1c2aaeb7bd0766c9775b8e5d0d5d3b2f74e29870509743c72f37b8f4b7e7d41dc489112442404799024cb6216df4e9bede5ebccc391201f92e36aecaf5e567ba49e6f43cd8e67d933006c449b304b26dc6206540ca43758c1521162846101b8ce302c8f848128694402ceffbbafddc471efbf2a0f7f47f7f66159d70a28aaddff6db96a8e3181471d0f33a30d7cbfd21d759d0bab5057e264c5efc8e9048085fe996e25fd7e81d34f2aad7978e16de75c49933a322e269386e81240bf2e6a380385a8fa2d224c77708ef385faa124130e479930c26252c63c43868fd0a0985256bbc0f4b54fafd5fbffcae8bbee8a5ffbb53c9e639ee97a3f94ef6fd025ad665c73f76066c364438d24f479f080849d630aa33432419215bc06ab73d444038b2dcc60f7ae0ff19786b59e3c67a086f875e3e6d5c8283df262f10c17186bd077f1ce50ee3fec41b32dfd4dbf0a98ac2e2e0f7e1f31efc3e89e142ce94047ce2e0979c72108717e350b11d02541138302b0fab7881381f5ed82232970f68caa123fddbbff35eef13f189070ae30d2181547b434a4985f090919a601c47e76439cfb91baeda8c0171ea73aac71884ce4dbdb8168cf84c2088609c22fab0154909440608c6ab06ea0e69f8e1c5cdf4f3729c68481e7f771e1fcf02adab30c68bf715eb4cac03de0fbc3f707fb275db5be077121366494808df6f1d271ffde51d9a7119bcf5675285922d82545714195d2adc7439829a6c6c227095dd67b11e39923adb0b791d4a421151bbb6d9dee7480987f6054bd8224343b9c8ade612ca8ab7cb5bbb9258c1f1b346bdd8c8238184a330e8fb0548248ddaef777858afbf9aa3ea8cae09e7149640004995c51236ad6b4948f0be2c8954bbed6e0212167d22247ae0fbe6b652e1ded1859b937a9af21ffcbd213148ddad14e9934b0c36f099fe1ca12af26f181bf70571b211830f84638e38f8fd9c7244e04bc8e1313ebf4aaeb7675e306e6774551a1104aaf92d0fe440af932aeff5b2e83f46e613edb9804d759bb89f555df49cb8b8108697a8d9d1852d3794cfb6216c25edb1ed831903d3bf4cbd4ea2bd45ba61824410481221b7dd20c923ec85eecfd63ed69da7a62a1fc1675527ad03c7c75044f0be5ec2e9f86c19065f6fe0b3036c4272ddfa6d7c0909b364809cb4aa9aae0a73c215c3f22691571ad61b4bb6a4c221098402048354a622b29c0907312e42a2e0f54323dfd32d2c9e2ffa4ce884244f048425134d5887b67feea748445f7b61e58d9b7ab9124892ef1770aea58c4f5d52af9e52279f7ee9891d5619fc8922e6a3d712630442224bebfa92058513ce4282b6a708886d403cc796124e6f1276ff1e2c721b892189eed67fd004705e36faed85aa2899c42074961ca7413ae8f6e2e00f9018e238633c3740a72d74ce71f3e239306b0eafd3ac314548d34623ce883622b2e77a0e68e5cf19c4f7670b483c8fad76aed1fd11c08003c21d57a867ca93fbb9018ec96c48ac92c168e7409518cc1898fb7f549d6958216268089e2c7e879138d0681ec7109d74f88517d47a5a774684ba1d7bac9fe0fb54a7ca67c4f67ef76cf1be31c6cae00b92d08325302ffe00159a648036e5af7d7bee5ca5d6a42eddb889dc59c996859964c201c9830908491a4438a4c421555401eb62b7491adbdbf0fc404282f1cadc5e2c91e8f75fbf70e58b6e2a9de22bb73c3eda7dff64df4fdaf48426a4f5f48ec38e42bc4cda69064a02c292086c213e9b9e90acff3604c49294cdc6ef7ac0564f2b3fdb51db10b9abadbb355803383bd61153e0949418fc2a02efc1ef0889c11612c31c71f007480c719cb1c0276d3e42b20a30bad79a5d77c6fe70b365ed3f71f6b4a08788df09d2060d63066cef7dbc5109ee6c8b88e7d3f3bac7c673d8f3d94fb8de24d689d6fe51afa56436a4de4222a4c0ca648cc149ce0f3cae3802108524c20b49434a1c52127161db099d1a1cefaa6a1e721e720b07c5a98ccc78a4ead44fe8bcdfddcf4078f7436fe0b305839244028b93e812e277c22ce144fb7f7cffdbd39310a0c792ab3022b37712110ab26d947baf9312b12f0d7b10e1f8bbb58801bc5f6c6f9f35024448a4d15d1394b5f5ff78db4d5fef24fb7e496c7a8dbb36afd71199154855e5231c9040c8d6e7b3e9d1391d16fda46d4fd940e236da11b79ed2b1c613bae3580bdbb846de40919b8ccd4215954c55e49718c2069f5189f92406bf8a200c2cf401c3f837b1c4208da30112431c01b43de3669db6cf98461bdaf6cc0bc69df24ada61f5672875f0594774776d499e16069c1d3f23ca4f18007dc9e6226af7348937ce1faecbdcdc338f776d1f396a4cd436d17bdb8c81f4ae8aa926036c4834cf3fa893e8f13e49428af6542ad416bf87c5ef7a5da716d4d81a2da11ca4328a79d9c983c2cb5044844a23c8966133a3e55d678ecf2d97f079f1fbdc4979bf918413bd7ec66763eace6860de93549e32b961b928cc452a2ab6bd05481c3ed5540430acf68e1631404a2444109940d2bcc5b9c78fb8fecda3c6e8fb9d39cee212d7bd599e13f4fd82dcb8f13d6b85eb763808019ca94428c8e6417d481e6cfb206f2ccbfb1edb9f0672771110db0be3b35e1edef594d5ae88af272cfa628e4c11c2a93fb84f0bdef02732450871febd59e4a3dfc3660cb8bf3d19abc575b1e786f17b76003e07f8687c59c0d73e009fe31db7f73d742f5be033d7b1e4e3887951621e0cecb2aac7ffae44ae1e2b02489c051608ab64141aae93dfc7e795b19b1b17a6d2e3a9b1b4f6ff32725deecd09b94654e6cc28b5c91831affeef6ebe476f25e61990f0a92ade263c5fc22b25c8b828090c1bcff5fc8516855a1dff4dc2ef9e641d38def51c4be5e2fdeefef567fad9bef52cf6071b6b3df883d629f5cb6e2a7d71c3ad4a1566cd3e7035b218578a780f361207a9aec8bb0a84c497351707abcf38beb7b588012c81e03d581221c98b547f7a5e1675fb25cd75ef2d7fa56cc4ac2671eb43ac074ee9131646757ce7d0d1a96fd69ba6d43137745977e0bb063f1bd36113a1d43c2c919024229c4868bd57df2b6b4fb9f1da3198767ffa8ad6cb5452375535a79ade507edb83b95fda1ec80b260b7caf9f53a4e54b9c3f9eeb93244c9fbcbab2a04a902aae00e3afcf1b4672a83e7760c1910a91b6fee5cd4e3e567330077d7ef861248910c1a022fd1c0847c6e21fbcd705e940a568bbcb5b87d87f3efad5c53fbcad09e18a7b7e6f7eaee678abdeaedcb2fc031533e6063b2598fe6ccef514bddea7e2a2f5f65ddcf393799d5c24fa76e2cba22ad94bacc1adaf518924611a1fe5f00a47fb3e6f3261bc6609354012cb4fa2e2ca162a34a9d293fb4d792595d21fb6beb70ac659e6a885f3057bf38980be4a59a7830ed63180b4d36cf4817faf6f1140db00270c88f7f505306ac252f95e45ad684a9d00dbde36545ca68f73e2802bda95b6844a9b09c3235e9822e34072c4b8abadbaa2b6bb084838713f7a207da886377c21da8db8ff385295136189c11b0712e40d15e055e213eddb8370f046164671bfedc17bf0cb0f7821fab369c30b1597cf5819a0daa0f7087007f6cd8b50e558abadabdd08d43322d70cb81eb98178c1502435380e1fe7418485088ee0b477dc3f5cb4b0f739d4ac0ee2ba8852af8cbfe5b309a72b35acd5802da7a52b555cb065ca2837f99d3f80903690f9de8231f0a9b8687d9c1c6373f9201bb363ef132ffa3be3d49f6e4df3c008f22ccc62f519212208def725e33b656a0874d715ef2f55be315b5fb667bce8177fb965161390002f3f8ed416ba7e261ce48e4bce1ad9de799307ee3fa505c6a9e0f77842527970f92b7fb409667c7cde867e679c68bf76ee3e87d6ef66f0fadcd3699f13e328dd780318c5e4b690dd44406464230f24a2ffdfc87aa5eeb32ad83d514a0cc9bca102bc4a7cc6f739220e84f8032931f88c974924862c1cfcd59418a4118c251f8a0311fef9810788e0401ad46e36a8b3dec0675e705d8be3906d348544d77102e2772634b4a04842913601fa7ed575e30d0346bc787c7d3be07efdfba4efbfba7afd7aa51e5970d1c33dd728b574c86f115bbf715566d5668fce988c8d823108f46a1a1d934158071f348e8066253242663a6fb9b98a826c67091897c4eb205904b9f4eaf2d90e03bcaefc715684afb767bcd86f1567971d45190ef840146edf4c508860c80054922cc2b81f045b1ea8ffb81601b40de0f7264984243a4d982bc655348de6b08b313ef4fd480209c7f7f91c1212657ab79abd6a2379a2641019d23e972a59a9c2adb62d64777b618983c2ed5bcdd5a6ba261bac38a805a58df9cd4b8e2e0c9cde835fc98d27269cd2c0c754455e7c81c64b9fc4609e4369c467e3e0f7abd01273ca4111ef2c81046c787980080e84f01dee648fb9ef78a50efd39fbdffb23a92245a2728e9c53bd90080d1bdb607cf3796b501a732b09140b91346489dc5f3d7f171c4f3cc7f66ac3db9efef8267dfe37fae0b6cb5a2a55fa7bf1dc052d30032a8e3188cd4b62c6e014e764c61fe0c6cc0740b2c4dbb69ea3d343f3a2f3f3b5da58d78d700f3266fb559d89d781dc0ff2a08f88f7150c852f854e75256ac7eb7d18aa9d3a9e722c51524c9f719822c3a91f14318ef92552c52da2fe99cd4efcb3741a70e72734d46aeb468e3b01818581aa582151a65d57f3813af096234d4248a8ac7dfb4e3a85a8807e60db535e5871ba6667b8dac74d02262506dfc2ce177efd82a34ba02ab20dbe00551179e9c45445369e6b0e7a7fc47bc4834f72b273e0d545f882536d78c61de856198b440f9a9731021f1d5076fcb8adffa64cabf38c52279f7269b8572f97605b1f51ae9cf4c70c247f714e79400405120a1312d2a1caf80882c2586f89bfb32d46afb30e734e5ce91af7ee993be8fd136074256f11a94a936e9155713af6315d060f5eb850a917ac1b9ec81da8d42ab5b4d110378dbd6d948a8e7f9ee9bb19acdfc5bcb0d81be87beff3989090917f1b6ddf469923a34919f5735252e3d69b4cee392489aad36feb0be33a2f23e424b399057af379f0fb23dea96ff0a594a40ea0d418b8d39ff283084a6ff13bedd86cef752ce94504fca7371b30021836c09daf50b7d4171acc543146437c3f474a94010c66ca8b2947a4a19e8db471b0338d545d4986ef6f63030968d101df84823481c911e9a00fe0907654554412c30eaa8a7c9c1db903e7b304b243124360f6e1ed35b60ae372edd7ea571d7f9d52ff6bffea03cf68cef8a0470fcf6b028e9ab27846dda9555c364f4a8120090ad94e3e053c59c0bede3ebb11ea0335f79e470f6ab6af5217be7f47cfe177ea710da957f707bdeeeeebf161bd9b517889236689701141c102c74cb091d635de6e7c6bf51ab7a0d50bf7fff7b867f7516ae9a6f96fbef6a38a9b67b13e22fcbd79c55410611211f17c1052c11d3c5fb6e8c62b51996e12459f842ab3eda2c053e0fa0d625c826c39d54da1932cfbabe46cb1ce422f871e6302922de6c5d9f6ef3edb19416a1101ffa18d096902c923da22ee9e09fdbbd1ccb8ef279c26b61150eb6530573a875be64ebf8a55120a12f9717df5250ed9f63001719b73a953e9be685255114b20011cddf6aa8af285c4b09daa221f6737872b12423591444510b4c18372256dafb135c0ebacf63df51ffdb7beb27b9f3b8b3ffe48a9cbb21f6c71b616756b1e53a77e2d14a2e1b4d0e06098a0484905f50758159600b66f77dcc9356b2875eff20f5ebefa3da55aed97654daead176dba75f9a9711c7acd2db5ef7b7ab1be6ef0fb331faa54aae18cfdbea959d38b8f0809736c58091cb8462922ca947a7551af05795d959a3b64d2b8c7f473aa52aace8f56aa93eb23ce599403dc44723c964c3ef63e97ad7163e2c63551dd10edc7387a8c56304843b0fe8224deed8d200f60841c29010bdb6102db9097b3c5f7495f5cb369a35f94b74504b4bd50da92feb1368eeab648403f6c803bd3d67ba1371ab905d9e8fbd9de73414a24b1ef89fe183e1fdfe1e74855f1d8c4cfafb6c4110efac39e222011c0b07ecd9e8ea974964c55149c1bcaf4b7575574a19018765255a425101bf88424c5e3b13de35662dc3eaf336527999788c0e7796ea0d719f085ee4c9dbeef254a65947578b6df14a56e5df1dacfa38e55eafa179ebdedba6b953af3b46b1ecdbac9f58cb2eea6e46c3ec2d2d1c03452856989e5daf14fe71e32541382e68316dcb5454b1a23efdc34e33ffade4b6a5ef6eac5faa20daa5f8b0509086077f5b0f58952b57eabbbf80e7ddfcddfbefcea174728755adb2b27646418fc6ca379247e06e38cb838f029f2d9cdbd34a8a1fdf897472bf5c519fdcfeea1f194d85b87ccbd286e5e4e5227d0d1cab98a449c027b191101210e1bf771b3f56f673a515f3287e27afc9c22492059f1fd9d8e20af3e23d43b1e9fe3b70d79c78bfd5763609d06075ea554dd760d66d7385d256e610145dbfee47cff9f34db0097910e2d0aed9f9119f7fd64260c29a106e5505bed4ce5cc0ab6f739b46f7c0405cd2791c8160e7a913de4c6ebb1faf757d1c2ab811c17896c1439bebd5959835445f94262d85955d11caec54ec64cafc4106cfc4a7c80ec2eafb3800324f476ea0cf78068b2aae5570f684ebce331a7b51e3d5a13821b3e5835f559a5ee5e36e8fccf6ed5b0c17b470dba5aa97bf61f74e23b9ab0dcf7ebe0d3bfd39cff83ed3f2e9bff9a52cd4765f69bac39ffb4f76bcdecfba3722bdc8d3a68d0361803e27845e478ea88b4ab8ee9a4d489adce3bf5eb12a5aee9f2e481ddce3133215332d00620632d491214c0e6d69b987cf857372f6aa5d433b3af29baee0fa556b658f2e77b99ee1f9de3495545d961298b2ca71327027201be84e3851ecef27de7e1e8fa664982be8b773d680964db043fc03dd3a7ea7498714119017a5eb519212f3ec9d9a26fdd6fddefaa140fc9fbf78083969a2b2cbcb7cf3946e8d4abad1a49f6f7bdbcf95284c44906976ebc7fc97eafebff3e2b54b3bd5b2297be5f6c1fd3f7ab9e44a9544c0209b0552675970e57efbd626d4fc581c435bde04d8a3a108ad8c16cfabe485b8ea0c5f5d9c2c8e888eb6291ca38b8189f377790c3d7399e71385e4ec09191cf8c4f65019f39a81d7140cae7c4c647e3cef6cc837c8fd8f8685eb23df320df37763f5dd75ecc73e2f71011efd68a508d7df7d587f680b48b5c63775a56fa88b326ebfe55e9ff3bff7c7d88df90727027d7bdf302ebf3e697c573de81efebf97e32125b7e37f580fa639fe7953af084762fbd3c4bbff67f3fbb6a66032de99cf6e484eea8494eb61ab2b900334b1454b8c84d5a57d466d34d1b8729f562ee0d573fdb4da987ac6ef54f82cda308b5cd8ba8521edc56b9a4aa2028e46de4310e77b5bae27d6ceffb7823c8b504e29d7fff3acc16df29db834f46906751b2d1c075b06dfc0e7bf978f0cbef71f0811dcf391139add8cd1be706a707c7c1c801aa32608d088c99a15da07bdfbb9acf6d3da254eb9e1defbeb6b5fb9b13553925fb7ef29c60233b9d5b4d9cf4406f2a40291132c15789ff9ebcfd05361035ce69eb524827a6ca21ce9f16b2a1bc417eee7eddad97f30aca0d4491e3dd252716a022607c01920479c17417712001a266a031940eced94974e422302d59c47b9c7bb113302f633ce30ed4b5621cb37d1c347d37db332f7ea78488c067ee1be2fdbe41f36ccdb71ad4d647f4019ddbad7afc27a5eeba3d6fcad36729d5eaccac99f5a71bcc64c4a7c871527171ae262af0739fc6fbb17330153ae21adca40213751c2a6103e08038e20169e5b97d1021bf6a3540e519a0e2daee08f25841a96daedf40c95a79f153c4bb23545c8d6f6a7e44e76f95aaf57dbde135a0caf4c5179ce2ed4b2f3c3ea8a4ce3dacfe99cd060c7b61bc113bb54eda9453b5c4ee24dbc722c9a54fc5458ceb3dce8d5638603cf2f7a0ebb6bbfd1546f42aa18292221b2d6c7fa9583351a4e2aaee4654c2ab2be64ee93d30a58a20b9178ce1f08778e340020f4cbff192c66dde83031203545cbce1c5c11fe4069ae535ee27cb6aec4b99210b606579239f39995fb08d27e14267154d775f4a19c918780f4210c0baf51b2c3bbbae52570ee85336b4835267bf7263e611879b1b3820d2dcc111d09c0d952ae751b658cae1244aa99271be7230f0887a296c047567e05bab962b89c40efa00e3f81ca45a0950716d7704b92d9c2e02d6af13e4841140f0e5ba0ae5a60edfe75cfdca0b2e69dd190499250d221c7dbd9024134eda8769f37903fd536d24612f8c271c3ddbbf38a25d3bfddf2d42758ee8a5e2bcacbc1a0635461acb03545c247fbf1b53614942e2cb00b1cbe6fdaf9040945ae9fe938093357de985b59da562b72131187c31774a1bcfdde6c11f687b20afaeeee2e097de50e2e08f335e7a0fc8d9d0698b0513ac230fe0745962f0e65e4a5691cee7c61cf112eeb848ea88171fcf4bf5188318beacf87ed21af28231487d2fed8f03ae54ea983bba341d74b05257f47b78fca9a79a275160241d681caf40c6774a6a4715f5446956999a8303e412a4e4b086a82b3ce30c8bef4fdf4f38353852b21611c881363f9a87dec2e92228075790e41e90be3d88a1387068d6e0b310e94c39957c258101397e8824122228749062a47cd0daea1fd582926fba04a4f165fbdf75bf6b7b8b387dddf9915e57beefe767a4bceb8af6f1db9a8450135e58bbaffd151288e3ec1bfd8fd886b0a3bffb7243f90e603a686c73dd76aa8ac86ba5faaaa230f0790f7e123163f86ce00b039ff7e00f2e8065c78f5b73f8e80b955cb650150573ba112f3e6feea504f31211f80421f78e3b4112cade09e7253901b4812fd93cd3c6f1be87e4d08f57f7a78e57aa75f38ecdfa7552eaeaa18f7ffe1fa8b652e96003a74c1b99664012145f52c08f701dae270984655b9ac9eabc77b292bb3102ea9dd720e3b82df0f9253d2ffe18e392f83bd9dca77de961286a75a8bb7f3bcdfa753af8ac3fff8579a1b81de9ce4dbf73a0a89438e860b3f1fb6e3fe8f6500b03da0610a174dffb16eb95473aacd673f25dca63e7bf14cf0026f97e52a20c92fcef756aec799560caee41eb8b802491577322471c78ca2ab7187ce8e894eb8f3a2a3ac9615c6c9659d8f4ad81aa28da6f6a38737d5d66b45f88ebc3e67a8bfa19c644a7afcb00be3ce0cb31f880bf03e1b3fa015f06f0e5015f0ef045802f07f86ce0eb017c3d81af27f045802f07f86ce0eb61f0619cb6790ffd7e346ef31e882b519dcc7bc7e605ef4df39287f7c8e17930cf198bf7c8c07bcc51b9069f35c58b8fdf2303f8f2808fc61d013e9a071bf82e02be3c312f11e0cb013e1bf87a78c63d16ef8179d0f83281cfc6bcf4f0cc4b18f394877e8e581f63715f06de639c15496dae5403d5f4a253b424724c9b335a1e788052cbd6cf9f3371a2521b37acd958f646f40e9f5755d581808b0089b0a0067cd59706aa3c40f3c6d1755ef7a0861fb86ecd6d271cb3efbdf746dfdb4af8de5966bde8af81f520d657a1585fb1f7eb81ebcc3c58c06f03df409a67e0abeefa95dfc906fe42c69f07fc9e75d1ecb1569fb53d4da95f52239f7d3d4fcfd18f15fdcb903287eb7e1041fe7fec7d77605455d6f87d93425540042c28a189065054c4b5918958f613bb045d154d5c5c0bbbbaea5ad6c68bbaeaeaea2a2aabd8829505549a28b6bc8080080a0a845e8288945002a46732bffbe69e73dedcf3e6e64d4050bfdf77ffc8cd9d7973deb9f5f4735175a864348f005fab8f23d561a8d78adf66295055e80da84b54ed3230e76ecb7be1993e723c3787b6f61c183b2fd4d316db777cfe2cd8c7b80f6d687786f9136afdeff8dbe62317970bf1ed639f7df15d1bf505bf0992bc14ab544d715018ff84296bc059c4372f0eeff02f2181dc141d19fba790a98ab298aac8f37377d4733e4e595715906ac7a02a1a047ef84c5514ec4e6950150d82f6deaa8ad0c633489718a261c66927ebc6cc6d48c973a20c9ec186e48d3383a7ab128d1203aa4e32992a918bf2ceded9905a766c7dc405170a71ed930f6f1adf4b880b3bdd7ce771db558f30309238659eaa4561e41547242e71cf45fd2a23bddf5e6a9ec4ebcb6783e2b60c068f3851834a2350d5c9e6c946fc0d363380df24bfd9135dd70b7151cead17e7a8882ee31ddc741737aab2186349e31c861adbbfb5e2a88abbcdbafdbea3dfab3767c9110e3d9bb2f4d26745431a06d5e6b642de3648fee2b53815d67e2bbf800472dca6018b410299091248624e761e719c4a62f0382613a7acda7e8e2b36ad526250ed9ed036490c45206023a7ec001e16937c4683c4d0d30278d02e619c32b63d7836c0d3fb313a5062c806780ec053bfb7e9f738ead88f61008f8f8ba3c1f3c6355fc3bb484fb5469c743f92f4f2138e4bb0c4a0de5b0cdff72389908fb30df0b2019e8e77913e0e12de48803710e0c5be0fb508ddd9ea62210efba86b8f4b24679679e5296595770931f7fb8f972f9ca43a0882882791a08aeb55f87cb3fe3d969804d2abcdad693f4a0964665f9040988457049c66969a5f39bbbd00efb0d66f2e591741db2459dbe2bc587334c033ac37b93e70bd227c05af00d65b364980198047676887e1779da1bb1abe2d67b769d3ab54888af3777570e4139be7942cdbfe817a30b24ad5751da106db52fd35aa26d604254138fa7e73467547553c49618a9440869ef9cf9423d708d1b6eed0cfa62e96df75b386b839ea1248946a7c69fe98a4ee804408eb5fce961aa5ceba4459f68fcde58be57bbeddf4d982ffdd12c80b9003354862c01bff7cc9e07e5e89419892cb9923de7589617192eec63c4d370ff4da575e677b2b3170afb3e00b9e1a9618b80d29c8f81c0ef03a1334bf0da794b95754baf1236d9f397c4b6eaefa653acb05c6d3de87e03e15ce10696e9ac78add6e1d0dca863b8e05c61a8cd846af35be4f4c81b64101abdeb86af0d10695acdb79b463746c441e34cd3f3e60fe01dfa807f815aa3cb719dd3783840258145f565847fcba8ba32adf55c8727d9c71fba00b9b49d27ec888ce156336ca0fcf1135ed068b04de71060d03cfa1166612a59df87cabdf54ff61a4ee67ef6940f925bcb0268b0bdda51a3547c6dab1b6ef46427e00b383df6c5c56ef4137ca9f4b554491e83f93aa88671ff63676e2033359af336f01da6c5c1c1d5e925e6741aa4454a1e181e71da81c5e725e6704cfa0eaf16ee84b8e31c88eb64542d0e45c5563d2404cd942aa18c8fde54b6b1f7fe09d2e5e8ad5a6f9f218988619224f6554a8f79bef139a271d9e699ff855b4dafa8a32c2170dc8c1157daefe30d7fdf99b73a7f57f44128c39cba6ac5bf50a8c539ca641ab71fcd0cd9aabb2b0c6e71847ff8babb6c2503baaf2a54587feb884f28c8acbce7fb6b5fcecbfd6cebe7db5759c2c83c5d78703ed2cf85661c1ceb7daef6ab250c2082a688bdafbb2af088863fe2ada29dacffdde7777b32f3216efb8c68399080c5fd8c8c13178f01c6e8ca840375e741fd5e179ef55cf7bf8c1ef710275f81e3cc22f0ccf6569cf65b17e107ecc26e0f5177fc7decb36b8cdee4a47424691ca8c73e411c71e7e0a6f9bf00b03bc2c8007e34cf8f171d1da1e7ef49e2cedf7997ab2cc04f3c6c68f71d4a6c8ec2c46c8bd718e3d5fff7c7d6bdcf8787f42f339aa6efab8aa314b715a1f55935b300b94730fbc68b598c4f0e7f3a5f0cc6177e767b1798efad661d4303e0a3e839760ddf0f1373da7e065b175c0c6bffcf4b2a7961f2ac4eb4fdebbf2baae42ccbafc8377173eafc681526730c21062f12029a648769450f8ef385c4e581ca86df1f394b00e8f13b810c75ff6eb8cf0a0b79a4b89e3efe2ed889b2a2774704a6bf79a01fff9a38fafff1c309e177adb3f9f317835732ab7b8297c12159221b138f0f95e1392fd4440349de726a134cadc48c7384d311639e8004e36c9c03684279fc3802e5b3da54b2222d9c036c8ae6a74a7f4738e85002f6c80a71bf793cf6564c7e38dfda0649426151771f48ca331b98112bc00d586cf4fdd2051993868c1545026bf777f64b69d181e53d5f58f7e8e0702651d86fb527ce9ecaf50351d704ce5122320a1fa2bdd83cdb88e094f76a1145f0f5cf5668a8f42c921f8022dd5662acf2857ed390c5fb67e2b9bedea59922bc4fbdf3d5dfa640b2176ff6dfb6d9590fa852ee462358e041622089c60e0418c07f30cfd797e256b8813143e1fecc027c212509bd29d936451c46a89d71f86dd3bbe5d7b29801e7269e64715f2b35353875df19248a4a2c47da69f0f81b9cf683e615e988681a940eb1ea919822978b050f24f07da9c6084d9f38d2628298dfd4172c53701e8d6261742a761bd0fdae2a613ff7d8b2fb333e43363acbbdadc16fb3a1cfb0d1a150792fbae72e7252323b8777aeebbea7932fa817109dcdbc85d6e20180d6d6bbc7a0e36201a154b7437586193fbaf03f0b2019e0df00603bc20774a1be0e5c1736180d719fa1706789d35f816738365c6359f71941b5b4b2c2070308ea399511cdf93ac1b730918a96dd113e015b07171005e36c0b3015e5e3cde16b963f371a179cbd3c6a5841b190d4e0925caa82ce1f5d2c6058e058417e91a79a542cedc8c35ef954dc25425afe975e40855d7bd0335b8a7d6032b4189b373a514734deb12d766d27d52dfbbeebe1b301571eb18ddad6dd66f72d7c5f953c65263bf8b58bffd4e0d6a9cb9bb2eed13b6de4ceee1b96a1e6be657fcfda7a38498b4f5f9618fbe2bc4b697366c2f5b00e3016eba649cc51a23fc0ff7be1f5635f2fec90709d1fbd3334eaeea20c4f799cee38b5d9bc0eafad7d13c4fa94f500586e705aabcf2588d073dfc1e56b02f69a0ec3b0c4992751ec30309c6000faf5bda8ebc3f5bc26d37e5c8e87bf3e4678bad938f9b20bcf92b817d9141fb42b54b02dce44df35744e1081909e18313cd0f672ceb375de2bd7cd1bc37d78e56f852668515aaae394cd564446781b3e8c64e2cb3037598b5a9ec2f0282290de4902c1f33a7748be4642a0acad2c66d11a2c3f0ce151def93dcde92b4944cf728a6380188d3002f1ddf81c90e86b88da90696792b91d74f31c17b12e0213fe3c05f3c301d06cf0678f900cf0678f900cf61f06c80a7be37c7afa836d804242169afe01141e4077f118367033cede017e02f6ee52bafaeb803d8d6c6050f7eee15e6793fd9006f18c0e3e3e2307836c0cbd7decbe357301e269fe62d3fe1b878de68450c9e0df0149eb83ef28931e0e31c7b3ed2ad6e4d453b21befce2bd6d9320db2ee6baaa03af2bcaa1f523b47f82e73022fd7555bb5bba456aab9b52df12a25bffbeb35d0212371e19301e05b1b689c099bcd738431486f9c47ef7032f2c07bcb0282e08c6b5c8b04f02e269eaeeabb24b25eb31f5ea510f3f365b884dcfae99b5f529180ff0aa425d3b72bc985b8cee673955882127e7d75ee31ad9971cb87ad09d52dabbbad9a503cf17a26fd6ef6b4fbf4a88c3da769b307fbe104be7cca9d8f19dfa5dca0faa2655d13aa851758804c78aef591ca180ef434868b2d9f3863ad405ea7cf6de87253dbde2e137bac8f79f939277d78bff91fd58d23ced1f43e56f1f11e7b51921fcf3970b84c45b9f0a1b1bf629329ab49f818c9ae62f0cf08a0c8c6c9e82b764e857d33f3c4988752f16cfdc04d71010e1c0543d10af43046425d490890119a868277813be11cb5ad6dee704046b9cf8380abfad6e4365e4152116bd5bb4e63349013ba6f578f50749e99ba51ed8379673e74831dc5531c8815207a0ffc0cc88b533920c6cebc72486fc464a0c3cb0ad1fb93be600bc0a782e0cf0d4f7268941308961a092182cb33bb00df032005e01c03311c091d0ee09e352c0c6458d53b6cf8d392f1e6f2e311839253a000338e7464a0c46b7584e004b48c244c62003e015c48f4bfd1b75a754b477737abe3f61ca1dea094e382867166cb8da09aaa61b0b7183c937b658d2bacc35ba776f79e2532081581a5e660267436f159ede3a56ed12365fbcdfc9ba41fb25eb0c353e89d7c3b496aff61d7eade468c72e1dba2913fa8fe3006ea17820d52c871a08894b582e3ff09ef517b712a2ed791d6f18fe9a50eb23cf5b07d68ad031ee3502ad1e6e3ffe1a591f7fe759d38f900758c6885ec76d7f46f26375b3a66c512b43a4c0418ea95342d7a9da4730f0c007c98552a7e4b1ef99ea8c54644840fe28c4b5473f34abfb39429c75d1906bfeb64b8803d71c5cf3ea03ee6f42a5bdfe22d439d459c4cf5f2e8c2f8e37b499c4172c49279e3f848f8484ef336034e6fccf944e2e43be75e38617cbe0de1e4e38709eaa0e5135057c82c44d044433028806023bf7310181ae7b0404269e7499c069b89cc7f20d739f59293770fdfbf56d3e937587c99deec85a289fc90c2d6bd55d98233739a7ec570da889f44b0cb1b6912308f2cb2f8603b098543b7ba72af222c79f04781900af00e0f103533ff8b9aaa858b400780e608307910dcfe5417f55bf8222de6d5225c201c83825bfc460c3731900af00e0357ca0369631f038bca41883c89975b67b53e197cefb4fb9174fb985240eccc68b2a99eed0060212014283a2bedbd316a9addbbb2aac6ec3fafe8b492080178c27321886086f5fbc8ba742b5e16d305f3a4344fb229badafa224256b580f5b42eb4639c38598fdf5843ed3e15c40d51d1d4090bdb81a0ea6ea6aa85f12e2e26db7560de82ac4a11f743be65177dc72459ebbbf7d2a185c076bc4d5ae9b6f4a76da9bc7dd2a0feadd6dbb5c2d259c7ef5e7bd78d1d342f46edbffde1692f5397848c721650749823664e95bbb17c9b1ffb0ae06770411162410261bcbc350cff0ea36fd0fc948bb5e883ffdf95f136ee821c419a70c3ae4e9de421cd0e5a0198f7493bf3d2fe5a053e4816bd55b9fc5bcf24c8c1b8e37ce5fae3ae502254aae6237cd5f18e099f659811573079abaf5e5766fca7ed66dab995af312cc17645e20427fa5375f6e410984c781f80888b1a4063db067058d374847c8bc081349815a80701db84fd63d2ec4c29e855bd63e22ff4fab5e7de345429c78cbfffcfb3f374b54c369b7755a2b1fcab262a61ecb89c606381ab662d0adc2289025f4c6828d8346e46cd08c0e57ee9e388d51f0c64211118d8c56218a8cf07b7c8f0defcd061b03a4d5465d24fdbec842235736c0031315e15dc8e0d9d00f484a6e156abf2f62ed420b47355feb07e201fdf5c685f0c987fe67c17b553fc17887042a6e1cf03d2a30d1f18d8b03fd0803bce1000f091ec7bb90c11b1e302e850c9ede8f4281cbdd06787c9c71ded4383d21d4f1375c900a2474178c5039d4f0b9053733c256f574ecc089c7cc9c078a7b636f769465242ac4990a4fc40bc6d386f9403c102f87b57deb187e57c4da8bf93804f43b1bbdef00ab7cd5ded175cb3fe75f28c407539f3ea26084faae0e541cb5a8aa02425b0381974848dcefcfeb79c359a7dc26c46129475dfff86cd7901e1d1efa87d7ff288e9d791d68f88624577bd44f42b41407d9ae4dbee767a7e5bb75e6a053d7efde2d71eb5b7b6ca1fca0aeaca6f9e276f20c59587fc94e8997b5c8aaaa7d57d6432dabee3e09efa1e8837592e4a6ffa5c9991d24614ff973da693d6e90f5a6d49d3d24c108cd0a1dd0fd18e1badb96346b26dc837e934be2093fc457e86ddff8f2f9f3cf271272fd3cf0ef6713fc22369fb82f62edc89c9a6bddfe57aedcfde75a60d0a3e0e480eb36fa37d6fe2bb43f869a393d245ff691048245526955f008038ae25369a1ce136d2572884aeb7f78a75c1e31eb2a8abb7c2c3986c31fed71e3c152226932b6594a8fdf8b384e99eb10939318485564d6ad6700bc028097586228a648f4bd53153189218ef3b6015e1ef4370cf0748981ab8a8a81e3251b922107974962e0c6ba71ba7343032a98c4124309937cc6412eb1814c62301a17717e133b51c4d990745522cbc155ff565d9e2b81cc5cfdc15353c00d1575fb5c678c9c760dd84250e4c7c86997536b3eb9759dcba1766b75e2a7779f1c9b1fd54fcf76941bc38324109454b9c417b08eb96acfcb999603bfb31aeab7cf763643a4d5cbfe7c3cfa95822786c5bcabf2cae1a0a9bd978d470d1b0ff9f980b4210f1cbb5588ae6f1cffd4888972efe6583bd2ddf4f716c79faf5f2e39027e41e371b035d55569a74453eb7b9c2b44da9f9a5c79bae49c9bbcdaecd9014325a158d874f039f2fbf4922639bf97e743bad5ec23377b70cacd6977f5970764cae294ea580e2a61e576f89dac57593531afbbeca0fdd6487c730d1225d700706711d3fc99ce1fc0b7eaa7f287d7cbf539ab7462d927304f2441a3e481f386f3f8a2aa2977d910556304bacf886e2cfb8a80ac5515a9b26c6823e118ad7f4f4a9a7cfdfb90e4f1ab36956f7693b22d1935f3f5996f4bd1f395439b96c8e70eac3e78ecc99273b4aaad9bd36f10f1c6db8c58cd554559b0a047e241a35445356d2b4ffee91d49b0eef961b8237fb9fa9905674e96846ae9a1b3cf99f88c105f1ff261fa98a385587ef5dcb61f4a4e6c7d9f65d33e7b45e2e594b7582c0f12eb71eb8f3b66bab103cd0f73addfd62da1264d8f168d5715f5635e6726a35ab2aaa27e70702569434ad6eb2c89247036c053fd26db4623bdcef801d2581b9281318814d6f58f1190fc0f9e9e324541226f95aba08ebb80ca2d3590dd170908dd0f2209488b6b5b2d88119009273eea1210d9ffb580871a8f121adfdcd8e7dca9c15b27b96c3c54bfbc75acdac1c93213f65b62a39e07d56ded9b95176dfe5a8ec32def5d3fb9addebf6a50752001a9fe03b45f16e2b49b2edddcbd9b10c71c715ac10b27b97687d0e466634522860bda7870e2fae5b601a3513fe178908a9933145c65c4192b4184541b0f09cf82b60e2f797c8be039d5c6649444b8a11dc40099e6af08090bacf702d82780eff6d19bbe58f06f21be7974da9a3990fc13558eb47e519204d51519d1210094bc1021a928b9f3ae1501c50a7a60ef0a2720ae4ef2d049dd9e7275c63f5db8f20efc1ed36ea742923bf4c76f0a2a84a6bf57350678b911c35d671ebff348d9f17e951754e43bf2bbb79a171cebe6e2416fa87ca6032e56edead6950f9648d2f16dc7699151db25617a7556edea6bd59338704889c9eb060f0cf073a7f4de70c5aa582c712c6a999b76b810fd870fbe2cdb8e39059c71c92512d7754d4b0e7727cabcb01596c51243b778d97dd5f79c2385b134e68612646445783d019e03dfea07bf6de294e8a056ef1d076f1eccbcce689c698326c6db070fae041e6c2d318c0b872734bcb98e7f1ce4fef2e08944e3529b555dbe658b104f9c73cd7537dca0bea850245b94dfa9d73b77aada559db80575fe683371ef0769f7c591954d9a0871eeeaebe76dbbc51d4fc4970869be1a2772ab1e0c6d07f054e36d1be6c764cbc8268239527b9f693db0f9af1f5a5f512d39f182b4bfbf7b8364782227d42eae8683a51c547ad5703570e5c7429cb0f89c8f0f9784e5a453cfbbe5c543e45ebe32a557ab0566f871f8e743db56fd84b6373ed9da78240f8faf2b9b8d8f93e478e07a56f0f269dd2687af7ffef2017ed03e407c75f81c5ff44e34ec8b65cbe7defc9a3c07c76e7e62cb44309ed37a0695eceebe7a7b273c873772220345f7e08057229edb2491f8cabe0a243415478e53f59005af5d23c49513f2ffe348c4ce7deffa9bdca4636e419b08a681c68ee1c6ad3c19ea7e42ac3a6dfe81ab25c57cf7ac870ef9e30f427cfec6e897cf6f2107e5a25d59731e1714a9593ba0eae61fa588376dcaab6fe47e28c4dbd38657dd3243118e458a57f50df46e10e5778197ce4ed0fd9695410d46d532d025ee3847be376b774169a9109f38af5df05e6f215efbf4eed6d7ac16e2a32f5e5efa876512e7c9bbc4f76e364e87451a0fa7486f88a43646d44380178b78775804ab17990d014b0111f53c72d910f14e11f78608e74644bc033c91a3c17344e27ef823bcb57ec4e1a7f7c3d123ea699ccf326f07536930c0ea52a84d11de384e98dbcdf6451c67b1dfb179308cc720ca80108def676044337c1eba2a34a78964d0aedcf9e07b0fc9a32863fdb119ed8ba1bf92816af141eb9753ff21c415afdf7ffc1db74bc23162e08bef6e9407d721d63897703436a23ec1ddfce184e3c13354f0f1308f0fc2cf6ad4789823f693c397cf5fe0bef2e1dbe0fc61060513fedfcf99de767eabd8933e8697ae62fe82d5c800e34e08439bd94278db5ff6b50d04240c324a4ae1ab775df83237adb1b52254f1fb3942342f6eb5e41ad9d1eeaf9c74847bd02f7965e69aa510928f5e1314405402801d55e100442501da192ddd5e2e37c0e267bf3ce5d34f2567b8f188b93f49ce70e6f071bd5e949cd5c6c7563fbf0d44710c84aafb93aab97b62f52950a397097a9f804848ba6008acaa7d06da40506ad17be57e49649ede3c7ed77342140f9879c8a7a70971d4fc7ef77791fd485fdde4c14e19223ea02e7176559f3714798f65c0a814c4fe722f1b54998c06afaec6deffc16d0f39ca46634d35a8b84a1a0e7cf4b929e6800e7f2aa89cb88a2bc08dd9a74acb010e8fe0311517a892226fd43d5d2e198559df4da89ad24e3dc9afb2a5f8865ba18d596613a9b09ab6badf5561753de784ee3115164a66e4dd47b622e51cd1ce375f05d04f9df3cc609c32f7ba9b0af04c2a2eb32d4a839f7a69fa55ade4baedf2d5710f9df3b614588f3ee37727ee12a24ffd590f5fdf4d4ad607b43cb6f7fb225ea7aff035ab3c1d6861bb00dab91afe45c6f5dbf07894c029e0ad2b1bc627a3a1f1f0e1ebc1c7534587b7a7f88e067826155792f87a92148e23ec0b5071452aeb6eda7da21013fb3cfff8dbaed7dbf3d1f76bd1eb0acf27e63587b6adea43551d81f88f48dc7a8ed59cc57284a1ec2b09c4863aacb75d82122d89c63616716896283fe069219a8d689935ea65212edff6c0752f7610e2d017ba0d6a0692890570b063f578510d1ed4a05270377ef48afa47aaa4c8fde9f3af4d9eb043882dd53f0cdaa2941ba26234d428e24d85badc507f08f549ac0df5eed7f59abeff9b1f5eed84ead777c909ffe0f6a77b3ff0a094489e297fed9b961e2722fcd9559d589b272fb4d5f30992eec5da71f06c8017067885002f0cf0d4ef1d8207fc46d48e7f2fa53a19674cfa662b780cefa0acc6e328058c03ef054e0e9ef75f99abe18dfda07118c752ca18c6257247dd0d55a09a3116c0c8554d265172155ea6943ad0366547c6f9f22545649223bf67e6988653c644fda931d838eaf88a2a7152ca979260fcd4a2b97bf3a0d526747af327e3e08775f8c29ce43321fe22e8c6cb64c70339faa0ecd6415761f36cd9fe248689f135ed37c7908cd4846fc0cda5512f755196363e006fc7d39b6efbee12d93ebafeaa7ac6d804d5285113033e5c6f071bcfb1ec2b09c456154a2014e1290956af57b35a5f32517e3729f47aef03848f330a7d9472bc1b917e44e7ccf1bde5371b6a965f39ed13b9be57edfe368a0405e0214f8057a9d45f0b35da2ac0bb00757a753da086c8d75a3016d600e789c6c26ac8c24a9208506cf2af46ef068c13000eb60e03ae90b2c34d6c75433c7c6a2755ad7139dd8d7d563d34fd612979f5ef37e4fcb9b24fbfb31e6bde3381c4c0bca11a8878571c2f1ae76c901838c7c5bca17c5e25dcf6e0c1ab80e7f43810b3f112df9301f0543f1a29319838679ff13d07e240a612e7efc05fe41463cf573f5ef9c5c6638498b3794acde72c25874f125d0f6d304252e015d4ae91514a20bd5c09a4cbd9277ca8241070b3e511e4a375af38cb176f14e02cc125b279e86d66bda0c6c710001a646ca6f9c73649b8ba445910606c3644bcc771f4008f38fac4f8068d47d03af02460abc1f14089b724d0f6a2e34bfb03e0737cfd124e627c4bd87898e62f3bb144b9e2866fb74f3a4888e5efcffb76354f2dc334296444875433a84921891a090ab03cfce64d73d9470484dc77c3d0c6009f755244be3c6bfd25cfc8cf2eb32e74233b4d399042a194f69daf13a2eb9613be3efb47c919fdabc5b5df5e2009caf815d377802d02fdf2a31950a384c2ae26c52b35d1eba0162e5ca96103ee0bbc398c7d8f6e8d2c42b9ee5968636e197c1fdead0d1213710a474aa9e4d31d6fb984e9d0a15d8fdafa2f210e7ce4e0d7cfba5ec4e78672605c0c0b8f368a5a685c555442eebb78f087019e5ae849aa8a28702a9fbc78e669f032d8c19fac1bb35f05930df01c80871bc606786a5ce80064de6c53c9edd10678093764e5985dc3d7ff20c4dce73e7abe285f0d08b9abc2bc9317cb36f8bcb5aa2371f387a5c531adb6b84e215d17f5d97df7e5c21dcf5cadfffc42a952f0c2ca40c2ccbccb3c6f9b0cd54f168887f032d90555662706058f474cfb097506e001f3448c40513cbe0d44bc27864f81a348a882025603c6837b4599dcd983c6a38445782321c88036a98c1a89af0dbf1f9de4ba2d32306ed98c5065d339b92efa85101fad1cf5e62b5709b17beef67fed06679e1af41e44c2810c32a8b28890c07986aa2bbae80b0849f2570aef2b0262e9757ca468afda33465c2c452f6b86f5975eeed2f74da0eef5639d16fae3c172800e7ea7e3c84193a56432f6987776ed9214f898b97f2b768d7e9f895118f18efef9382014a888feceb7431b6feac203033950a0d048209080d0cd5e90248e72c8408ea40824e5237f6a885846c907ef808eb01bbf5c896a45c6dca295f2b93e9d063c30d09163f46eca336d8e12892486d871c775a10d2c6c95d2c39c1b4a3def71a0ea3d9c132b21c9a788c1b3019e76f007725e96211300da623c5dbb0df054bf4d9cb945fdc0f88af60d8dcb8e6ea55d162e1462c1a8cfc5dc52d5614afe87840475c567c1e760e3c21bf68880480c5b0c3cf0ab5429a97439fcf8f6b15426b61c319180131d0d190bda91575c41accd75e1e61b367578f3005e18bcf6826c443c62da1ff18eed5c68dbd04b1d9e39e2bd40c3d78bafc855fd4c52420d1a0fef8e70be0e6c809f9b683c8c11e445942f438797ac44cdf11d4d84a933400def09be3edb11c47155dc5dd66ce569427c3ee5ad411f82b71cad5b94a08111260d0aba65e3f9067504d631119046abb0f6b51756186a5b55ee104697467fe72e85e8708c1c661703a1ce2f076f9803c1ea44f117d76ba4cdaa430e7a401ec4397ffa7bfb918b85386475d75e6d2e86ee3ca4bf1e25109400e860b848d55520caa14e1cdb6834a71c3f6884fa94d56844afd56b5489d5a228f9771d8e6694bf4df472fdb2ab6fab983c6b56bc4e95bc316c6d5cc2ccc660ba000bd3cc07a46bf7ebb27db61284a7dd2f62d43507a453275d3ed90a0c69c54d1760719df070ea87cdc6c5d1e1a9e777b62f7d68438ff89ec6e980d1eb0445f941f13d10dec6c2dafdee2a826543bfb2b4fe23fe7863a27f7c13dba28cb60c80770cc04bd646e4e8f03cdb00c337783d986c6709e1474d17956519f0f5db067478a6eb068cb61e80671bc6c3c33ffab3e0ebed8f84fb2d597ce3c6db01fc63f0d6a62d7eb6507d425e56116048f19ce3353d870c2cb381708211ec7d85653fb9f152564c2726265d1de3016c66546513c8af8ae546d5f4639be566c95fa414a6a6377b4241483b5bd598fb069540a4ca8283a3f628a841e423d10e233991400021c06c95946c0f251a3e610fe8cfa34aab96a5bb265d24720892a0943f525638fb766d5c007bfdc0a4833f7861dbb1cfd13dd1605c361efc85fce0f719f1193cc3c1cf1803e1dd07720c3c67c37bf1a077e2e105deb36293317310eb874650715cb6166f68bee16dc03c6aa8c350c3914fe6704e7050e48fc7d74fb0551b8dfccc88ed1df4cc481e4448f98d9d821b69099e0e9f5f49ccf1e54661ef601bde20bed1c4f07df3c40fceb03e1e41f7d724bd7e931d0f8f9014360e5fbe1f38fe81fbad30197ca3c01846064406574909d7f96cccbbb3e09c8b80ad1755ab980414cf1f1f21c15c576cfd1221b1a1764492655fabb080705072b33f0a9179e9e9cb2e961243e8f194a1bd5a8a7811db89fd0645ec7e24f229674b6654adfbbcbafd5229397cf5ce84f1e3c72bf898251507060f74cc361981ab4beb20608602c230491e1a495105863ac223f59a6c2dc8a1420428ea0e6942a04d4be95a68db50e7aaca750a68ff7da7c56e60e2c11b3a76cfeb171b1701e352a08d8b29402a83b9fb9580111d5551c62494f07ca01137c9fb243c5d33aacc04c02b80be2b3cf349459003fd28827e08c0bb2021defeb4f5086f18c0cb4b3c2e566ccb3aa78e99f366aa10bbc66c5dbb1b22d16b408a20d11f25d1f7554dc914d1af1e55586b85687e6dab9b5d1b48977f1d7f674c856572cfcc82c0bf5250010645201790f13917e0d9aa5f002f53a9eaac7949ba419bdd4975f85c05e3d9063a37882fcb2e8b2a4a2f4b32da06d87a2b602a234fa55a04fdd2f1f5dc5cf3607c747864d44f723c7c467db2e1a8b6d10941cf864bf8fa03406d03be5632f8e2fedd7cfaba99d31f1262ceb153de980daa739f711c6bd4702c85ef8151e6ce3ea44a87739308c75a9164d9d76ebc50280ec4fdbc507ceebae5468d2276142510bc7a3621e5aeb4cb5f5b0321f878a73546b0f3ec9ba4da824339ba48d5a4e2eaafd7148063727f43112f47ef2fff1e27884447245c4ca27125a19297163df5c381c03917261a97645545b00cc62679039dff0e7907dea3493e283144fd2a3487c1d32506136767921844e3541a096e244cc8d955debb7b841b67f4e345cb9d1d10df518f841d6be4d0701e619d906492150f512fc6f51c656ec6d186dd338d9c2ee7948b991bb449b517ec4ecae13bd0ce6a14be519f0a15f177a09d95103e735715413781728924f9f59b783c7c123093d01a8b2f977092c557f8f085f18fc676d2b70f7d72e23450a993648192076388a9e64e3c78ae0d8f7f63dcfa86759f7cd9df91e8f92eb58b2e720fd4a829421323b133e9ea59f5398b742defbde3e09f40254577599f0b35de690da9515250d21aa7d7bed425583342c007d8a8fae03527282c429426da2520172ebaa5ec5cf7dd910bd60f4d342ebe71c8d2c74fbfe3dd1799edbf633c8bc1d3e7c31f819bc9e099f00b27c4cf1cf91b4e8c9fef3955fb2295c1629163e807e0b1be68f9c58ea3c69b083a4a9c98c281ab24f1c229e4d490c084a196906b2ea84c71bf378e0bb6bd3be5c31afee6fe373c3fc1f39595103e9f87ac86e1fbf0cd6a1cbe41f823bca4c7c3bc1ff66c3c4cf0ccf39914be4111e441e381eb7ee1cdd327bfb44c88efbf2e9ab61abc4b6b98ea9d246696fb0a55f474f32012129e34d16675d2657f131059a2cbea2f8805dc393aa729b871ce33b2ab360f3c3a2c7a76ea230a26e5d24a5575ca0055d3d59478c10c3a3c16072019065ce1e06ffcc0eabf23420470894021018b272c9dc45a37d797715cfc014dc3d53b98aefc18c691fb395a5bc1d34dc451936efc18e6f41066b60d8749263e9d2eebc73144c6b3583fc21ade6663a8de8f418600c22c455abfeb515831076c6534de983a871b19f17b4e4060c3c5df35bdb3bc343346801e12ff709d217cf36653ff6d684735fcb9edcfacd3d7e77131049e9a6c45c1c6db84fb2fca25493b495b94095ff3fad2e16519f0e53699e16cbdf9ef086fd478c449128e86af49b2e6e3e19f3f24a476427c93b5f501be9fbcfaba331dce319238507381b656544d611b6cb8c408e17d1f1ac6c22f493ba291655f1110c7fc55b42a5ab77b72fc428bb283868c51902b891d3ca0e24ae99352d9748e8210429515a685c78baa30fe040909deb4610332e1807ed801df275b108e03356c299cc8fa7842522a3a366d1a6b6a1bdceffdc48cac5c45402a0ef5bc77501b1676d4b751f48dcd5526fe833f0af08603bc30c04b7cf01753ee2ffd20e2c64b5f843033dee2861c87c65c1ddeee8edb9f5b364a885537ce9fb969930248aa4bdc58cc8b8502510d91bbb46e602462df1d503f77f71d22fe0009c3b8e8eb39300239ca0f7a369e001f72a7892423a68d077d6162959979dd717cd97c717c03545c81aa5aee1516a4e26a64047934ec234c3afcc68f8703edac84f89abc2619bebb7b6c3f78d915724d7e5977335d7486b60c76f119d52871a06603afaa652a793a7f6ca8392149baa4ece90f1b2e74e564b65ebbc6f4a33a9dbcb4c7e3525a589d3ac4cddf2f20ecd0e2c62ecfaf9f5d15ab9e8ffc3552b863be102b3ef87ae32c50651185c6fb1d1885ae05ef1b8cdbc0ab4cc938be063ae0ec61c74d65adaad0b980dc9a95592d2621f5fdf8bc875b7f22c4213bba0cb957e55eca73cd701633629b8c96be34e03960b4f522bd99511c9e4f36e23d13ee519907f79e987270251bf19e09c6c5798d355e1afcf3b32097582904d6c1b8ac1efc7dcf897f95ebe41ff32a56a0771daa00c0784e990720130119d3c11859f78eaa493201824359a6d7c9ee743d7df2607784fa586d3adcd3c07af6ae3e56fd2d51712371f3383a61ff0d7152749f0a18ad13dcb0a9569dd159c2179867011e0a7e70c4b4d520be682c6611e409e280549ba52bf7dd6343c66780b79711e45e3b30275972e361c16e0fbe262121bed18b230b2bef12e2c3ba178f72efa4dfb162d3bced10c85a839932c0385e7505b4d1688e1933307e0d8ce518404d57d776024c6ca197b5a291655f111038288970a064200fcace438eefd1fa2221d2bb37abf9c3dffd1b830e9a7c4ae9a17be9c042083d9532c935962fa99d593ab59ffa0239482420387058534a0a14ed56a99a544c9ab02d3c4e736dd25d6fb8005c22b050bb12d2299f5fdcefd85b846832b4c5c0bcf31b1897d1466f1d5c88b1b748c2910bed79f1ef4a7a6197b088e47970e1559037d4681a35fd60f2a7e2600431e00e79cf6b09068f6df879ba5757a46fe45c57d29d78e9b377bc243754f5c6ca6995b0e16a1981c08d878484bc5bb6c3f390f61ddd26f9fd36eefaeeb1fed4bb4f97eb29342c745a4f77a4bcf4df19b167319dbbb79e470334d5ffe4d37fc7e049c2d11eda70877ec30c460311deb9eabd041fdadccba8e1886923be2574db4f1ec00f27c437e8022c824f8c8f82976c04b9613ce292992a784111e441e3c103404b1a87efa2d367747b79b910df144cfbf762c8d987779863ba7dbccf03e3d7f08228b4819084020c129e733c43c75eabe8f71b0141159294400ed8d836afa25c8883761d7aea5fb6c69eb2dd5427164fade045c4ea17f0c084847aa40c3cf04229ea5db5fda019338428fb7cf3524caf5e8ba94430e508729c18d701a947ea4e5035456222655e0b75186aa771fd37155f8a171c9f3784387ee23983cf1a2025b3c969a75fd025f62d1e98ea692e3114b11b03b9bb6e0e480c53496270e02f2e6c07e0a9dff31b036961c3c6c88103612acb32cb73701922dee3e0a9f7e480c43015e6976fc41276d079d94a75bc9153a4d41e8af15877d992c5932e1562c16d9fbfffdd0ef502cab67ba55e1321c100529448c02db20e52dfa06a8b245528ee9dfe479dd9efd9ae727da76c4ebb23fbcc04e3eccf8eacdae608f20ce87faccdddb825398afd5e0c84f1f3180c5b835f409cb30ecf8bf0566d2f82bc04da61c05f27fcc9e2eb3120d9807f18e01725856fb62f823c4383e7112a7d7d992454c12ea82aa10baa609e70bd353227191f0f8b13429e832b31bea5e11f87bae7d8077ff9f7f4f160abc5f55ad941d5d570052d12106ab3c067241c18af863901298d3b128e0ca81db187653f1bd15d0e7ffec269f76fdd26a9e2c591655f7f1dfb340c7fb9eed38e7d1ea05befbaf1844bfa834a81c79d58d3f5766809d4ef410dcf939b31d44438c27bd2cb0485c121028bef7384481b94bee1cc0e0d1ae7c2f0acae733605788d6336246f9c193cb49d446df81c6d1b4e627849bb2726345a12dee358f661a1eb861b1df15e0c92c7a8baa9ee7d318591b71f9806e9f82909226c28f44ae13a65d41d932d84b97b93111d4614379e4b58ca3a6ceef4f129c26ccb209b1ec39fad676f1e13dbfe087e0ef08d30bec66cb3cc481e940d37c17c35b8ff8cf84669feb212c14f1a5fbfad445f5ffe7da2e36bda27c375a7019fd38879fd363c1ed1002339b31d96656d39f3fb4b84f86f97c7ae1f05aa27be3ec9dbea13bdcd039fc9db0a6d1fe814a28d54dcfab5c55e967d2d81600d3c6bbc2aabdb8d271edfb6af44e180f4c2ec6ce10f6cc36cb2fce62fa64b6dfa5ccb6333e494fcd06a49e9d46239a89f55ae40dd208a6e38b0357de073e6474d5e3638b0195017409d0bb593f410e805e090ca231f6a49d8ba0ce993e7ba21670ce9ddf7b977e533b345bb666e3a787f6e28f576ce819902bc7c3a66e08882ef90470e0990060e330738b8a94c22f4020805c02b0078c8e13a002f1be03900af1fc083d131a9d0b8caccc0d965aaf69a59dfcd1f3b4788ef1efce22d37e7955b304710e604229515ba3fb2eccb6803411d72046e2624093517fbaaaa90942c4b9e5ff8f87629011f7ddc690b2f973db3beb1cadbdc1e879f0db63e5f7664d8c619600bf15424163ca7da0520bfc2bc490944a9140772152271dc20491247afaf03bc2a958fa7ff8e70862f9754c9f696789de52699838b2495007cfd39b8747c4d7790737c4ba85d00ed8c84f0837292f1f1b04833a0e019727055cc2d5bbe42128c31998fce78f2cfb10be9dead5059dcbc24ae205954808abe1ace354ab904eb95182134a2a35b3ad451d4b020abb6166a47ec65d9c7048422ad5132c0a48af2e06cdbace3dcedad843860c94157fcc90d04f4eb3eed584dc9e9885eaa361c98d677a122f74ef4832e3c2cd78df45ef3c682d71740a01837aa9331e946a89c40844e00001c4c494441548f563511103ec0af431d2729c44a41d008e8cf63fa79b27960fd8610e7e5dd34e5afcfc8a9989f3a6ba01bc9cc23598dc66538e84daa01cf58cb23bdd5f7a6acaa5e1658077eaf36ca545fe4b80df032009e03f0f483df3b386cf87d1ec0d3dbc9a6e93644bcd75d573d73abdc80635e7bf4a0e72546f56323c5b4119173830d59c5084715e89089a383e474987433f2aeaa697d20a3a18e742d5968f793fa0d3d52129a50e79473faf513222ec2fb3ce8474b357e487e0c4e249e0a86cf9b1a9781e24ef89d9a67ae82290960300cb6810446774bc737c96cb8088fd2aa9b549e0c7e10befc8ef012dd0943f0bbf80322c805e2c79d46b88a36d9f1c880effd8c500c5ec5e96597af3c5c88f71f7dbaf8898142ec7ca1f48b5d23142052ad628e3e24202a6da6a8445b0710125ad7a8ba02491a8de5513cd710d302a81df133957da4c2f2b98539f0392a3fa46835fbe5f7aadc2b69eb2745be5fe2c66570916f38a6232711d08e871265ee726daf3cac26679110bd1fcfbebef72dea498c4477534dc4ea54a8e1e0c038120c34a4c875507d910405dd2042801fd8896bfa1d7b3e0484c855ad5dbae9ce4fdd9bdf52e7a7df606789b8c86cd93311a7da493e3256570d7891de8e0e8fa98a7c11ea0655d170701b0dcac1956c72442f729cc163eec64946bcffd86e45e9e7cfc943ffb29a7198b4323ed23f56b37b3f303b29cf0c40eebd90a286447f4d7927fc81a312a3dd39db8f8e397570f7cce110f7e2b079f4bb4367b17189c6f797543c6341c56b52c1f0e4a449469037a092dc337c93cdc165c697c38736c00b7267770c714b368f0351e3da08156dc2f1f0abcad4f75b0b7e3c7ae65942bcf5a2ddfb61596f5bfad3573bc0664b2a299028785257aaabf5e729fe23ee8efed83b794034f608199f9fadec2309048bcf688c072a06f649dadef44f2dfff985e4d8da2c3fe4d63c5b7e38445c997a968873df0511d0a6fb007201a6a380c0e79d24cdef2244bb778f18786e0f210e3feae84d4d25e7b86ae3b7abbebd50bd0f250fb1595538e05658c79328354a1e79f09cc5fa63196ae061425d549df206d4b25f7f98611f7987241ccd1e6bf9d23b6fc7f0bfc6bd09ce1a692982d98e386d8585973e3bd6ef38ce477d6e037d2ba1cf15073412daed54d8a4275930d54891d07b65c3b89690224f00bcf3005e4b801706780efc3a03e0091d3fa62210d00f0f3fa1e3c7eea7b0e17e8d0ce20033a09731bc4b5bacbf64865c4fe3a63e71fd9beb152c727384ab91dd24746ea9ac84fa23a8f17bf072418e8e6c2290d9a01eee5b201516f6240c354820d65a2901bfb7e02337434297bb8f1fed322e299bd2569d7a6aacbf5ba0bf27417fd702ac0ce8979a37baaa18dafe7156e3d142cc85b68297cbe0d9d02e61f06d9d538ee3c4117e18debe36beb77b8a6f9c4a2a0cbfcb80df69f01bc037231e5f092f17da1abc24f05d0bcf69f88acea442cdd84bf8561c54b1eb93ad35df3d23c4c42b9ffb6fbe3c0767df38615aa11c89bac2da372a4f56cfa031bcf272a8c1468b2a2bba39b55c7f9eaed406c983ae1960f11e941b1025e7b0f899cbbe22206b55c50f54aae1407603fd36ce5bf5df8a17e4869b7fc2ea56f32547fe4adaf893dc3cf799a02ac19bd73c115e9125aecaf1bc7e6cb76afa5c8bd37af796cd6f7b8fe8305872a8ad97dd33e75a79386cae7eb60e0e882824d32333b30df88d66fdb0597f4aa0ee9cb89f2120182e0169b1bb75852be90c3af39ec71e7958f6efb5d4290fb8aa3557b4ce8bc33b0b44e1525da71ae83668f2563224eff379bf08dffd0628723b002f1be029afae71e0d5956df09b174c0565ba002b0bf01d872a02a6d20a5069543d5df1c98f438578efdc27434f1f283793a89a500984826c19c8d1018120f747cc828c6ebb702f0ca9acd05f1e37e44dd0339bd5c81001d10ca1a429d77575a4fc964552223eb453f727af7209d349e2fa1603ddfe820d299bcd9bffceed0c18970218171c67d5f6bcceb40baa8c49128bc88b4d87ef8f7f2881b682674892484917b97b31c3d7536922c3e24b9298781d9bf035dc116ec2374e15aa8f8747a8d4fa32a8b812b8cd17c17309c763d103d35b3db750128ebf8fb8ebdd1be4e1ffef1dcb773daf3acc250db2c5c14da74450eed63f47c607555c787f0dd970212720b9e9a2a4910bf55a56ff6c655f4b203a6feb3b8051a5e346924746d7dcba4812920e83babe78b514c9acefad1db1886cd3c499379e5ab0a0534fbfa859e55172223b457a2de9fa8dfc608bf871999c98adbbd76f2d03ca4d8403f1c40e00a123c20747381188e9ac4649a3ab10170eb975ed09238438ee8133ad31f2fda1d294f3738a85d9f6309a38fc5ed08f30f4836f1085add948e7403b57c1838ba54c07465080176ef42230daf6f319156d784a1dfc4cf7eedb881ebcc457bc06300675ebaa1fdfb64d888faa47e53f9a2e259089eb5fd90ef7bbd4cc5775d58150a32482840475c84860f09e179438d046862a0030c247bf861a3839ea890d6dc650b846f5b2755b46b917f6742aea1d71df9b3eaae91167a7094f7a4932dbb037cef0b6305d58a534e33970419527b1e23c16a8e78c362907e021e140f8b6d6363318050de34bed5c6823fc0c866f4663f025781ec391db20bed90c5f6e7c2f315c5065769bd7e0572d2e9fb74eaefcef7a177ef0a29ce79967bd37eaabff516fc0839e6e38854040b46de07ae4711d14df012a2b6474284d3bbbb08e240e18005dd92f7efec0682afb9880709b001192d150838ac7dd78dbab373eeb0ef89107677eb6fb39b9e1ea9b7d73b69bf77e2d898ab15fc771140d6e3c1ed8967a54faca0cf99e0ed33a77bae023f99e493dffe3265dacaeaed8b25a1e183b976c5982ba47c28fa74219cdda923368726bf359a9c70a3170c4b067c352d239befaec7f3c2027b669a4e588a7fe251fbada6ad9f1558d3382b1600b3a0b16b05f62009c92f456f2e00d03787989c7854b0cb8710c0158283194ea91b7be48617ffc0a124001f0543f82af7885a29eafdf56d7ad5c4a8c859fbefdcc637f1262f5b8ef66fd78bd7a0275c1d540389063ab423f79241ce82f8f5e56e8fe88de2bb821d1f88812ea5ca81dbd26f76f201cb46e60bdbb12e8c6b12b2f5c7a8f94b05f3ea1c9204990ac2facb456178b78d5870db0800c41db81b6c7308d86e7543b0bbc14e7f99c0f54db8bc3d0e1d33e22950bc0c7f887c632180d1b9b050ff84c94665fc39718435cb70c3e6314397cbf338603fdd4e163c4bbe72596110fdfe42556dea6ecc3e27652d2387c7ac757e53a99d2fe8587dceb017ebc6bd93f7f04152a19b7c1890319962a8c244723394a1ca05245c281120a8783aaaa08dc881a05c9c3678b43e71f5bece362edeb17c06be03d3c4e03931ea681313b1db2e8ba92c785b7dc367f4c441efcebd3c79c716302a0e835918f1c056e3cb0b4302f1df937f6bdc854df5b4ba03ddd4a738d5091acda794bffe306dfd43ef68d94546a5b57d72e7545c86662612cf9e3fbd1735ddd64ea75e9d9ad1748c2715fb3b4e3a4089a529ef6f7134e907d3a36f4524f0bdea4b0092bfc8833d217348f1c1fa9ae26153d415564764b74183c1b5af9f09c7aef48c0a3a7cfcdd186e7f2015b354e4101592381e3ed0957a8261f399db81f23ad6206cf4e342e91136bcfd875bbe4ecc6bd3ffe09294b2dba67fa8c15e025558b374c822451b156d5e570e0574c55352728da8d9022ce888e81573ced35b27636d4d84324206ae42969273a6de0f5022ea332a0e2baa7064bd6a0d5d5ed36bf005e355a31a878e2ae12566d1ce791c0680cb362b7e1906dc3e78d67501999e68d477c0b7695b23f50af61f8843f5b7741f8227c5b87e7c13748508dc5d7a25974e06f0c5eeddc9aa1dbde938ced811b577dfd8410cba7cd9d3b5dceefe2dfcf18ba0a24803a8c2fc2b000583f64ec46a70dbc89146d17d3f43649c4681c47af2a804757d0a2b11c53eaa0713cce89c3ebd9fe28fb8980708e8d3878880b41ef28370bad5b9acc16e2a4d0f965279e28c4116d7a9e3b65977039aeacd08c04b0935dc818998d777af7b496a8e78c0bcd0678c87939f07bd5ce5407a0dcbe08af51073f7172f970f0636ea825a45977183c1be025de807c1cd086b4c41adfe0b8e081e1c1b313e29d0907fd126b493cbcb87ee804d10e509564423f96f8c625d6ae3bba7a52694f213e7fe2cd371fffa79438ae5f70c5fa6eea41221c58a3bba38af116e519d0863ba3c9f8788ffe3b525d419c10110ee6b54204841592aca107c418a1f7df59aa4e4f97df6d4fbdacc59d52527df0cf47bcbe5b12971f9b34397b5642b0e1186c0341250913d7df12603c928fc8ce0f800f8c888f21083ae8f708de1ee08bed86096192f856f7ad18b16eb41065af95e62d1c24c4da9edf977cf59510dfffcda95bbe5ccefdb0fa1f78ba7fbad707af65c0005538e0719dd1454e6cbda2ea94240cf41ac414242ce0b50e08d1af877060d95f04c486d7e5eb3512129f24d244d5cde4c171f6eb43bfbaf926210e98dcf6837b6b1b78879f6381cf6921ab8d96091c1bdb781e8e3e0edf8196612383e4b3c4d20e7e12817df0020e7edf01dcf00649000fbe050e3f0c07bf6ddc70221eef2424869e498d8b0f1e7bef4838107ad281107bbe7c6259ee7229ea7fb2e3b5839f1d21c4c693579f5a5aaa20d2d5c0b82181d3ab0209a37c34d4cde1f37bf4e790f3abe191bbe8b6cb7204910ed916890b7cce2511cc029d02eb192591a6d708d17e52e72eedfa0b714ad5a54fbd7fac7c664cea573dc618e0c7dec118172eb10e03c685136ce3fa0b98b7b0228b494b9241490d6d80e749503640cd07787663f0956d0bda084fdb17d173c4e31139af911935f76dbb45ae99ba9adc2d72c757e6eccafba1ab9428c4c6c3dc388c1f1e5d72ff324920567fb160e5065085f20be47c17ce2121e1f7f9b01a1916f2ea83f54636b74ff59a22cf791a76765f8def7e22241c36d48ed8cf657f11102c0ebc16365c0809c9c3aa46498436dc89aa6ede498801cfe755e69508d1ca6e97769f7b80f4b7ee4bf9d2fc2adf42ce018e2d7fcf2406d9b2e1398535a492900b3e1fe0393a3c347a82ca2ce8e0cf018961fcbe95188c9ce71e4a0cc62ca8744018086026a962b2dd0db161c1aac953ee1062eafd2f968cdd2237d55335a328391c120e4ce980c645201095a09aaa28811a545864f3c0da94b204bd590ae3474a78571507dc1f432a5a6c2363849208aceb26c818fd8f109dafeb73cae12b84e8bd38fb8a172f97cf1c9ebee1845d0dbcc42f61dab136635ccceb5967e37ceb399091311026801f7db07eb49b4266e7275b2f9e7f913ca85ffbe9ab457245576edcf5c3767990d71d53f38d6b634c7ba7c989ee78a4ce6b729b2b99a57d956e357954b64f4b3fc35561a7be9a36d3d540847e48f92e458e636453dd37eebc45fe5377b73bff7503aa8b5d9564ddbdb5396ebb6af0ee27dda499a57f5edf7fcb9f25c3f1fdea66db24618e4cab1b42778023c78e71122ca54784a5efaf67f7c3d0818e8403250396361d3f4755a9ef9e8ed3d8f3a7eb35bfbb9cd6a549e2b0a176c42f54f63701b1e1b5b8e48157456fac14d86828fa37295375b335aa766d23279f77f16dfde5001f36bffb09fffe56c23825b42866943415cfab44bd3570e3b1837fffa98a748981ebc23de3a281c3f71dfc98fd75b07a6fa0c460033cc3c1cf556806db4b902a11fa119952fbfd8e51422cc8f96ce9c85e427c73c9b4260b2f553fc4540cb54cc4279515c66fa0311209489eaa2b5bc2ef180748120712103c60d0680e88373a4b293c479208ae6bb489c4a9b2dc8237663695758b49ad171df0b41059b75df5dcc30fc9cf8e6bd9fad2850dbc0bc7196d5cc3603ddb64fb53d824cbb8980807ad8bc4b6c5e898e83dee3cfc74cbcaac09b709317bf3fbf77e2c39ef9a77ab5a2381a7ecd8a822c403d1a48a0992f84c05558dd0539a3f06bf9ea9244d0403e3c37c3754627f0c81a73c7715111aac9150601bc7e30b563fa8f7e397575599cafe2620581c783d974450878c9208184b9b422ea2780eeea892df3dd6ed2d218ee973ea8dcfb595bfc94e7bbc6bd706de693389616f5545392213e029c2316c2f554539f0fbf12431c0d3c9a98a3cce9071f8811243e283df67bc25788d3c90b00001ab4cdb55b2f26521a6f71b33f8b94142ac5b5b7cdf46b8cf05ef6f41af28ae2bae42c90309c7eff436facfe3e7fc821d9fc4f173e992e179eab1a32a7e23661a787fa5dfa66a97d38ed510b0e8aeeb339ddc19d77516a2f5651deebcc3f502cb12592989bc253361fdf9254cd3fad3b08c9b371b7e8d8c87056d058fade7dae6d54fbbf335ebbcf7224f0e940464d0ca8f36429c0c2718940980dfe5cd6e7e345d1d1dc859db7ad3a77a849a130eba629a110aba480c250f7ed531339a930481eeb568f4fe34f1f344a8b8c4838ccc170ccf30eb8f2d7e65e5972220581c55190989ba5849a44352bb74b8e33c9ddd7ddef42b210e38ba6daa1b887852eb0beaaeee2844abefdb3d79ed9112f6ef43a52d2ff0bfda7830db49aaa08ae1fb9e012a013341417836c0432fac868dfb6663a52e998c037883c17b2a799db80df06036e0bde3008fc181de2fb1bca9e5cfee9cb0e43f42ac7867ee9913270a316fc347b316b869f41df1003f68c8fb84491ca4b262de2adc8b8a9e0337dedaa374f868f44482810705cec0cfe62f0ff07c84049c455220a0311572b5e19dfd2499004171d773ac2dd779ef36d9d13edb85e8d4bff7c45b8f93cfa6349b7dd25d09df1d56ef6ea4d7958111e0eb7973b8e483896592d9bfe98d4563c7aa5fd2018ac6622018949b099358a24a0725402e8920216964c474b430f1f3bed433d846c28504050809d9c0b8ea88db401ed09fe384019faf636d7e11192794bcdfbe6cb98ef895965f9a808455e5db70701422e7950a3611748f4c3f1b6a20204d58ed66b76d1fca38b6dd22218ebd7ac0ca6b5e17a2e5e96dbebea052c2fe38e5cd56d76b38d80a074b3f3083365e26f3ea1a0c9ca07923db002ff1c18f5e35681c35d9364c07bf4f05e56b3b0c9e0df0d4f7a05a6bc0ed1302fe40e2428ef4b19a9ea512e3ad9ffc9839e32c218a2f9b79fd74f98bb5cdbfbf7f03dce4176157c6e2c153fba3aa310090a7a9f6a5b166c9e3f84155cb6e1c347a55617b5fa9046c55914a0bf6194a22b4aed1c88e5e88404888419aadd74de5e77dcf1ff8e619723c0f4b3d6ade2d9240a786d29b76a98e7bb78971e15e7f06e378dc7a89fdbeaa7877c6f24385f8f0af2fbcf7d0003987436b3f22f767640018c1e7354a8475ccbb881376ce69277dd5aac37e8f6d4e4870fe1921a9e777e1f7d7db51d6f6d559ec775c1565221836c3b7b1aad35fbcfcd204048bad2ada700ed4209c23c7461b0f75caff50751ab8ffa69fa36abef15cf7e096d7b4296bdd5d88eeb3fbbdd2e72a213a0ce8f2e4f9e7cb4df942cb97dcaca9a11742e9cd9b37a8ca11f1d8c5490ce3e1533cf88be27e9dc87dd70178d90c5e36c073e0536d63d3c1efb36518085631b47b1a545c49aaa0eaff50bfcee520abca77b75c2125c1d259eb87cf6d21c4bacb8bc38bda09b1b2fe9bc37f7073419d1c9d100952013077c71a20e4d518498e5e2aa60389130ae6868b1ca2cf5f9e7174fb4d97eca88aac6d7f56750ae43e42552d7921028344eb1925136cc7ad6bab87f559b3c992efb8b17fc7e3e43ee8d0a1736d7fd9df961fb69978861ce7d4caf45d47ac4e5e051ab7de62a742746474b4eb7cf0e584ff5e7aeb07426cbc7ed588cd2079d432af218a6b401b15c63540bb0a02e55045c9bd8be88a602d8d6123ca70f63bd6364a24cc1642073c12166e8b40c26070f32655145799fdaf2118bcfc5a08081647557cc385e046ae14f0d622ef16e4e0b0c68d0684c5c7d1dd0e6dc829e3ba0ba7b6489bdd649610873f7ff42387ad10a26ddee157674889a5e9a52d7b1efcbc7cd79d69fd9a3f21eb05a9bd5db76271ae382d66244d17b70b298358d789d6966ba65e635d163357cfc4ce58eabf6fa31fbbbc9e351d7d73a01c27ee73793df97b554055261ea68d1d3b4e306f98f8a3a545c14868f00d40c88354227f1400d1528a93e9640c8d7d6e5d690d72554c91eeb52fbbc6ceba3135356e246cedef6aeeadb85b888a93767e503641884da135976ce821c44fafaf1ce0065445cba2371087851bcaa0cb454242e9f499b7091110943ce0ae7a327aa34a04dba7eb9f73a324e215015b0aa620f1795519541efbbc38aab2c01d3934186a201cb89e7d9209aab8205e240dd63512942693a18608658ca3727f77c83fbb7ed05eaecf76e7747a24a3408803fe79d0968e574bd80fa51f71e005f25d57a655bb0c53a87d685e6c9fac1617c5d6e36a71ad0b6377687b97b5f2bfafaa26f4f902c697e21ed046850404558ba86a646ed3e8d6ca0908a98ad841baa72a459f0462806bb2b9f822ba79cd0810ad2b0e2fcaf037e0f3db2fbf360282c55115b78dc091e88b64a774ed2099e0c6a30d88f524f81c2384e1ea5b4af3ce3842dcd0a87a203ca08d040efc9de880301d509e1403c54efcdc2f566cbda9df151827f2b31bfac81889124090dba3e1c6359e769d7bbb90b19271aef5f83ecc5d05d996f906ffc5c61bf0b0b6400d0c11caa674632632486c5d23e1f0a970e1c2b42613a1fd28fb1d3cc709145d5b10d26be6f6e071dc502301a13bb7d1c681b6282424a8620406006d56e4ccc024443a786df6fea8d8b3e2c0efb3d8e700df47580ceeb151ae5ae370b9e483bfe34e00765258ff064bea2f8d80a184551505fffb7a68a36da41e099f03356c083ad06003920a05366064a0aae9c22048934c04086be00029d0110906236016a45ba65c48904c11d2047a0707271c581219437fc1421bc881f69dd0fe5055f519f0f965d0462323777fc47187f18d407a6a1e7055cbef35b8873d87aa29ee1f8fb60d788e0e80c5806f0eb47f2dde2b8eaae8a081839a0e1a94111f60cfc37a8b02475f0f1c7e3decdb08ac331cdfda93549d066d92d4611e8880601be0e3bab6eed4d18ef685f7fd0dde8304e478a8e1fd35f03e5235a2c4c19c1de8aa55945819e72eee177b548c84e633f61caeef0758db81f619faf74420f0f3fefae7bef7ffeadc6cf775f9b54a2058d41546640be1b612baa0894b26c8713149220db262a68277174a22292c9091736c248120e140a328e0451120889f8960fc468a89e38a425aea7abcc9112513ee478fa91e78ae206ca36482de52dfb1e7b0662a325299e1c6e64671201ce2661dff5f5d715485f122dc7984d617974cd8ba4e05556c1aac677e711aad6b6088683da35718638cf8b50bf52c4e069d2188016092087762e0dffb22aa11be2db4b2c792475071003e974cd8f77cddfcff235134b6fcda090896b0aa9879db8b0076544d073c2728b86160a3a5409a6fdc70c499618dfefbb0517d2a2cdc70600c251516120e5b47ffd74a507c1b83d5dcaf9e0e6c6efb084a01c1b2dce24152f72c7c0e048908467ff67ee61f6f348a23e108881cffd594b0aa685ddbd0b6f49ae2499071428282eb783bb471fd1a6c2bb4aeb9ea0a094936c30f19049c4f1637c1bdaa7ca93d3070ee741d8e31cea1b1c56175234bd0faffbf12547e2b04841747559c83f3d94c70232201818d4784856d241fc1e01b0d37f4437a5b200119ccf0b493e9ccafa038ac86c28dcef5ff85cf17e9df932d020ffe00b7c7084b3181924994fbc9f33aace3f98bdb367eae1256156790b05f5c32a15429b85e0d0c135fbf21b6fe79c4bcc5ce036e1ce671124448b8a4c9920e22e1f125a774f4cff7f8e076f6f2f7ff57f6b0fc56090816aee2823679baf7841a0f7eb8e8c5ba03da904f9f36144814a1f17a9b366e2fd606b74a52619da2a3479fffca4b14dc33c558f6c538fdfb285c901385c0309f3be42068ff57afebc71a3e8700d1e8013a1cb26160bb98e1395cfffc7f5de10c098c0724bbf1d61facf310ae532619a3b797f51eb4c71bbe5f92f8bd34efc83030b757f2765bc83e8775500fb632b84d9f728b91ca2a47fc5ff94d97ff170000fffff898dda83e6a16740000000049454e44ae426082', 'image/png'); -UPDATE PRODUCT set PICTUREID=10; diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql deleted file mode 100644 index 980d37d43..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/V0004__R001_Add_batch_tables.sql +++ /dev/null @@ -1,81 +0,0 @@ --- Autogenerated: do not edit this file - -CREATE TABLE BATCH_JOB_INSTANCE ( - JOB_INSTANCE_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , - VERSION BIGINT , - JOB_NAME VARCHAR(100) NOT NULL, - JOB_KEY VARCHAR(32) NOT NULL, - constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) -) ; - -CREATE TABLE BATCH_JOB_EXECUTION ( - JOB_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , - VERSION BIGINT , - JOB_INSTANCE_ID BIGINT NOT NULL, - CREATE_TIME TIMESTAMP NOT NULL, - START_TIME TIMESTAMP DEFAULT NULL , - END_TIME TIMESTAMP DEFAULT NULL , - STATUS VARCHAR(10) , - EXIT_CODE VARCHAR(2500) , - EXIT_MESSAGE VARCHAR(2500) , - LAST_UPDATED TIMESTAMP, - JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL, - constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) - references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) -) ; - -CREATE TABLE BATCH_JOB_EXECUTION_PARAMS ( - JOB_EXECUTION_ID BIGINT NOT NULL , - TYPE_CD VARCHAR(6) NOT NULL , - KEY_NAME VARCHAR(100) NOT NULL , - STRING_VAL VARCHAR(250) , - DATE_VAL TIMESTAMP DEFAULT NULL , - LONG_VAL BIGINT , - DOUBLE_VAL DOUBLE PRECISION , - IDENTIFYING CHAR(1) NOT NULL , - constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) - references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) -) ; - -CREATE TABLE BATCH_STEP_EXECUTION ( - STEP_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY , - VERSION BIGINT NOT NULL, - STEP_NAME VARCHAR(100) NOT NULL, - JOB_EXECUTION_ID BIGINT NOT NULL, - START_TIME TIMESTAMP NOT NULL , - END_TIME TIMESTAMP DEFAULT NULL , - STATUS VARCHAR(10) , - COMMIT_COUNT BIGINT , - READ_COUNT BIGINT , - FILTER_COUNT BIGINT , - WRITE_COUNT BIGINT , - READ_SKIP_COUNT BIGINT , - WRITE_SKIP_COUNT BIGINT , - PROCESS_SKIP_COUNT BIGINT , - ROLLBACK_COUNT BIGINT , - EXIT_CODE VARCHAR(2500) , - EXIT_MESSAGE VARCHAR(2500) , - LAST_UPDATED TIMESTAMP, - constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) - references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) -) ; - -CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT ( - STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, - SHORT_CONTEXT VARCHAR(2500) NOT NULL, - SERIALIZED_CONTEXT LONGVARCHAR , - constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) - references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID) -) ; - -CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT ( - JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, - SHORT_CONTEXT VARCHAR(2500) NOT NULL, - SERIALIZED_CONTEXT LONGVARCHAR , - constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) - references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) -) ; - -CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ; -CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ; -CREATE SEQUENCE BATCH_JOB_SEQ; diff --git a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql b/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql deleted file mode 100644 index f34cc3507..000000000 --- a/templates/server/src/main/resources/archetype-resources/core/src/main/resources/db/migration/h2/V0001__R001_Create_schema.sql +++ /dev/null @@ -1,132 +0,0 @@ --- This is the SQL script for setting up the DDL for the h2 database --- In a typical project you would only distinguish between main and test for flyway SQLs --- However, in this sample application we provde support for multiple databases in parallel --- You can simply choose the DB of your choice by setting spring.profiles.active=XXX in config/application.properties --- Assuming that the preconfigured user exists with according credentials using the included SQLs - -CREATE SEQUENCE HIBERNATE_SEQUENCE START WITH 1000000; - --- *** Staffmemeber *** -CREATE TABLE STAFFMEMBER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - firstname VARCHAR(255), - lastname VARCHAR(255), - login VARCHAR(255), - role INTEGER -); -ALTER TABLE STAFFMEMBER ADD CONSTRAINT PK_STAFFMEMEBER PRIMARY KEY(id); -ALTER TABLE STAFFMEMBER ADD CONSTRAINT UC_STAFFMEMBER_LOGIN UNIQUE(login); - --- *** Product *** -CREATE TABLE PRODUCT( - dtype VARCHAR(31) NOT NULL, - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - description VARCHAR(255), - name VARCHAR(255), - alcoholic BOOLEAN, - pictureId BIGINT -); -ALTER TABLE PRODUCT ADD CONSTRAINT PK_PRODUCT PRIMARY KEY(id); -CREATE TABLE PRODUCT_AUD( - revtype TINYINT, - description VARCHAR(255), - name VARCHAR(255), - pictureId BIGINT, - alcoholic BOOLEAN, - dtype VARCHAR(31) NOT NULL, - id BIGINT NOT NULL, - rev BIGINT NOT NULL -); - --- *** Offer *** -CREATE TABLE OFFER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - description VARCHAR(255), - name VARCHAR(255), - price DECIMAL(19, 2), - number BIGINT, - state INTEGER, - drink_id BIGINT, - meal_id BIGINT, - sideDish_id BIGINT -); -ALTER TABLE OFFER ADD CONSTRAINT PK_OFFER PRIMARY KEY(id); -ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NAME UNIQUE(name); -ALTER TABLE OFFER ADD CONSTRAINT UC_OFFER_NUMBER UNIQUE(number); -ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2SIDEDISH FOREIGN KEY(sideDish_id) REFERENCES PRODUCT(id) NOCHECK; -ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2MEAL FOREIGN KEY(meal_id) REFERENCES PRODUCT(id) NOCHECK; -ALTER TABLE OFFER ADD CONSTRAINT FK_OFFER2DRINK FOREIGN KEY(drink_id) REFERENCES PRODUCT(id) NOCHECK; - --- *** RestaurantTable (Table is a reserved keyword in Oracle) *** -CREATE TABLE RESTAURANTTABLE( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - number BIGINT NOT NULL CHECK (NUMBER >= 0), - state INTEGER, - waiter_id BIGINT -); -ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT PK_RESTAURANTTABLE PRIMARY KEY(id); -ALTER TABLE RESTAURANTTABLE ADD CONSTRAINT UC_TABLE_NUMBER UNIQUE(number); - --- *** RestaurantOrder (Order is a reserved keyword in Oracle) *** -CREATE TABLE RESTAURANTORDER( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - state INTEGER, - table_id BIGINT NOT NULL -); -ALTER TABLE RESTAURANTORDER ADD CONSTRAINT PK_RESTAURANTORDER PRIMARY KEY(id); - --- *** OrderPosition *** -CREATE TABLE ORDERPOSITION( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - comment VARCHAR(255), - cook_id BIGINT, - offer_id BIGINT, - offerName VARCHAR(255), - price DECIMAL(19, 2), - state INTEGER, - drinkState INTEGER, - order_id BIGINT -); -ALTER TABLE ORDERPOSITION ADD CONSTRAINT PK_ORDERPOSITON PRIMARY KEY(id); -ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2ORDER FOREIGN KEY(order_id) REFERENCES RESTAURANTORDER(id) NOCHECK; -ALTER TABLE ORDERPOSITION ADD CONSTRAINT FK_ORDPOS2COOK FOREIGN KEY(cook_id) REFERENCES STAFFMEMBER(id) NOCHECK; - --- *** Bill *** -CREATE TABLE BILL( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - payed BOOLEAN NOT NULL, - tip DECIMAL(19, 2), - total DECIMAL(19, 2) -); -ALTER TABLE BILL ADD CONSTRAINT PK_BILL PRIMARY KEY(id); -CREATE TABLE BILL_ORDERPOSITION( - bill_id BIGINT NOT NULL, - orderpositions_id BIGINT NOT NULL -); -ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2BILL FOREIGN KEY(bill_id) REFERENCES BILL(id) NOCHECK; -ALTER TABLE BILL_ORDERPOSITION ADD CONSTRAINT FK_BILLORDPOS2ORDPOS FOREIGN KEY(orderPositions_ID) REFERENCES ORDERPOSITION(id) NOCHECK; - --- *** BinaryObject (BLOBs) *** -CREATE TABLE BINARYOBJECT ( - id BIGINT NOT NULL, - modificationCounter INTEGER NOT NULL, - data BLOB(2147483647), - size BIGINT NOT NULL, - mimetype VARCHAR(255), - PRIMARY KEY (ID) -); - --- *** RevInfo (Commit log for envers audit trail) *** -CREATE TABLE REVINFO( - id BIGINT NOT NULL generated by default as identity (start with 1), - timestamp BIGINT NOT NULL, - user VARCHAR(255) -); - diff --git a/templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp b/templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp deleted file mode 100644 index 2cc1238ba..000000000 --- a/templates/server/src/main/resources/archetype-resources/server/src/main/webapp/index.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<% - response.sendRedirect(request.getContextPath() + "/security/login"); -%> \ No newline at end of file diff --git a/templates/server/src/main/resources/pom.xml b/templates/server/src/main/resources/pom.xml deleted file mode 100644 index 15ad71c4c..000000000 --- a/templates/server/src/main/resources/pom.xml +++ /dev/null @@ -1,167 +0,0 @@ - - - 4.0.0 - ${artifactId} - ${groupId} - ${version} - pom - ${project.artifactId} - Application based on the Open Application Standard Platform for Java (OASP4J). - - - ^spring.boot.version^ - ^template.java.version^ - 81 - ${oasp.port.range}81 - ${oasp.port.range}43 - io.oasp.module.test.common.api.category.CategorySubsystemTest,io.oasp.module.test.common.api.category.CategorySystemTest - - - - core -#if($earProjectName != '.') - ${earProjectName} -#end - server - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - io.oasp.java - oasp4j-bom - ${oasp4j.version} - pom - import - - - - - - - junit - junit - test - - - org.slf4j - slf4j-api - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.codehaus.mojo - flatten-maven-plugin - [0.0,) - - flatten - clean - - - - - - - - - org.codehaus.cargo - cargo-maven2-plugin - [0.0,) - - start - stop - - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - [0.0,) - - jar - - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - [0.0,) - - run - - - - - - - - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${project.build.sourceEncoding} - ${java.version} - ${java.version} - - - - maven-surefire-plugin - - ${oasp.test.excluded.groups} - - - - - - - - subsystemtest - - io.oasp.module.test.common.api.category.CategorySystemTest - - - - systemtest - - - - - - - diff --git a/templates/server/src/test/resources/projects/basic/archetype.properties b/templates/server/src/test/resources/projects/basic/archetype.properties deleted file mode 100644 index c27bf35e2..000000000 --- a/templates/server/src/test/resources/projects/basic/archetype.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue Nov 04 13:27:57 CET 2014 -package=it.pkg -version=0.1-SNAPSHOT -groupId=archetype.it -artifactId=basic -earProjectName=. \ No newline at end of file diff --git a/templates/server/src/test/resources/projects/basic/goal.txt b/templates/server/src/test/resources/projects/basic/goal.txt deleted file mode 100644 index f7ffc47af..000000000 --- a/templates/server/src/test/resources/projects/basic/goal.txt +++ /dev/null @@ -1 +0,0 @@ -install \ No newline at end of file diff --git a/templates/server/src/test/resources/projects/enterprise/archetype.properties b/templates/server/src/test/resources/projects/enterprise/archetype.properties deleted file mode 100644 index 3a6c3a731..000000000 --- a/templates/server/src/test/resources/projects/enterprise/archetype.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue Nov 04 13:27:57 CET 2014 -package=it.pkg -version=0.1-SNAPSHOT -groupId=archetype.it -artifactId=enterprise -earProjectName=${artifactId}-ear \ No newline at end of file diff --git a/templates/server/src/test/resources/projects/enterprise/goal.txt b/templates/server/src/test/resources/projects/enterprise/goal.txt deleted file mode 100644 index f7ffc47af..000000000 --- a/templates/server/src/test/resources/projects/enterprise/goal.txt +++ /dev/null @@ -1 +0,0 @@ -install \ No newline at end of file From e761d65fbd00891ded7ad82f06da60a612752d9a Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Sun, 24 Jul 2016 09:59:04 +0200 Subject: [PATCH 15/18] #7: changed ddl-auto config to update --- samples/core/src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/core/src/main/resources/application.properties b/samples/core/src/main/resources/application.properties index 097c5687a..db2e9d3b8 100644 --- a/samples/core/src/main/resources/application.properties +++ b/samples/core/src/main/resources/application.properties @@ -10,7 +10,7 @@ spring.application.name=restaurant security.expose.error.details=false security.cors.enabled=false -spring.jpa.hibernate.ddl-auto=validate +spring.jpa.hibernate.ddl-auto=update #http://stackoverflow.com/questions/25283198/spring-boot-jpa-column-name-annotation-ignored spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy From 5280da54e926bd49f84c2ec2f0d9426a4db6bfee Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Sun, 24 Jul 2016 10:00:27 +0200 Subject: [PATCH 16/18] 8: restored latest OfferDaoImpl --- .../dataaccess/impl/dao/OfferDaoImpl.java | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java diff --git a/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java new file mode 100644 index 000000000..5d3cb4e3b --- /dev/null +++ b/samples/core/src/main/java/io/oasp/gastronomy/restaurant/offermanagement/dataaccess/impl/dao/OfferDaoImpl.java @@ -0,0 +1,181 @@ +package io.oasp.gastronomy.restaurant.offermanagement.dataaccess.impl.dao; + +import static com.mysema.query.alias.Alias.$; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Named; + +import com.mysema.query.BooleanBuilder; +import com.mysema.query.alias.Alias; +import com.mysema.query.jpa.JPQLQuery; +import com.mysema.query.jpa.impl.JPAQuery; +import com.mysema.query.types.path.EntityPathBase; + +import io.oasp.gastronomy.restaurant.general.common.api.datatype.Money; +import io.oasp.gastronomy.restaurant.general.dataaccess.base.dao.ApplicationMasterDataDaoImpl; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferSortByHitEntry; +import io.oasp.gastronomy.restaurant.offermanagement.common.api.datatype.OfferState; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.DrinkEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.MealEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.OfferEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.SideDishEntity; +import io.oasp.gastronomy.restaurant.offermanagement.dataaccess.api.dao.OfferDao; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferFilter; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSearchCriteriaTo; +import io.oasp.gastronomy.restaurant.offermanagement.logic.api.to.OfferSortBy; +import io.oasp.module.jpa.common.api.to.PaginatedListTo; + +/** + * Implementation of {@link OfferDao}. + * + * @author loverbec + */ +@Named +public class OfferDaoImpl extends ApplicationMasterDataDaoImpl implements OfferDao { + + /** + * The constructor. + */ + public OfferDaoImpl() { + + super(); + } + + @Override + public Class getEntityClass() { + + return OfferEntity.class; + } + + @Override + @Deprecated + public List findOffersFiltered(OfferFilter offerFilterBo, OfferSortBy sortBy) { + + /* + * Default error handling + */ + if (offerFilterBo == null || sortBy == null) { + return new ArrayList<>(0); + } + + OfferEntity offer = Alias.alias(OfferEntity.class); + JPQLQuery query = new JPAQuery(getEntityManager()).from($(offer)); + BooleanBuilder builder = new BooleanBuilder(); + + /* + * Applying the filters + */ + // Meal + MealEntity meal = Alias.alias(MealEntity.class); + if (offerFilterBo.getMealId() != null && offerFilterBo.getMealId() > 0) { + query = query.join($(offer.getMeal()), $(meal)); + builder.and($(meal.getId()).eq(offerFilterBo.getMealId())); + } + + // Drink + DrinkEntity drink = Alias.alias(DrinkEntity.class); + if (offerFilterBo.getDrinkId() != null && offerFilterBo.getDrinkId() > 0) { + query.join($(offer.getDrink()), $(drink)); + builder.and($(drink.getId()).eq(offerFilterBo.getDrinkId())); + } + + // SideDish + SideDishEntity sideDish = Alias.alias(SideDishEntity.class); + if (offerFilterBo.getSideDishId() != null && offerFilterBo.getSideDishId() > 0) { + query.join($(offer.getSideDish()), $(sideDish)); + builder.and($(sideDish.getId()).eq(offerFilterBo.getSideDishId())); + } + + // only min price is given + if (offerFilterBo.getMinPrice() != null) { + builder.and($(offer.getPrice()).goe(offerFilterBo.getMinPrice())); + } + + // only max price is given + if (offerFilterBo.getMaxPrice() != null) { + builder.and($(offer.getPrice()).loe(offerFilterBo.getMaxPrice())); + } + + // sorting + if (sortBy.getSortByEntry().equals(OfferSortByHitEntry.DESCRIPTION)) { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getDescription()).desc()); + else + query.where(builder).orderBy($(offer.getDescription()).asc()); + } else if (sortBy.getSortByEntry().equals(OfferSortByHitEntry.PRICE)) { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getPrice()).desc()); + else + query.where(builder).orderBy($(offer.getPrice()).asc()); + } else if (sortBy.getSortByEntry().equals(OfferSortByHitEntry.MEAL)) { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getMeal().getDescription()).desc()); + else + query.where(builder).orderBy($(offer.getMeal().getDescription()).asc()); + } else if (sortBy.getSortByEntry().equals(OfferSortByHitEntry.DRINK)) { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getDrink().getDescription()).desc()); + else + query.where(builder).orderBy($(offer.getDrink().getDescription()).asc()); + } else if (sortBy.getSortByEntry().equals(OfferSortByHitEntry.SIDEDISH)) { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getSideDish().getDescription()).desc()); + else + query.where(builder).orderBy($(offer.getSideDish().getDescription()).asc()); + } else { + if (sortBy.getOrderBy().isDesc()) + query.where(builder).orderBy($(offer.getId()).desc()); + else + query.where(builder).orderBy($(offer.getId()).asc()); + } + + /* + * Result + */ + List result = query.where(builder).list($(offer)); + return result; + } + + @Override + public PaginatedListTo findOffers(OfferSearchCriteriaTo criteria) { + + OfferEntity offer = Alias.alias(OfferEntity.class); + EntityPathBase alias = $(offer); + JPAQuery query = new JPAQuery(getEntityManager()).from(alias); + + Long number = criteria.getNumber(); + if (number != null) { + query.where($(offer.getNumber()).eq(number)); + } + Long mealId = criteria.getMealId(); + if (mealId != null) { + query.where($(offer.getMealId()).eq(mealId)); + } + Long drinkId = criteria.getDrinkId(); + if (drinkId != null) { + query.where($(offer.getDrinkId()).eq(drinkId)); + } + Long sideDishId = criteria.getSideDishId(); + if (sideDishId != null) { + query.where($(offer.getSideDishId()).eq(sideDishId)); + } + OfferState state = criteria.getState(); + if (state != null) { + query.where($(offer.getState()).eq(state)); + } + + Money minPrice = criteria.getMinPrice(); + if (minPrice != null) { + query.where($(offer.getPrice()).goe(minPrice)); + } + + Money maxPrice = criteria.getMaxPrice(); + if (maxPrice != null) { + query.where($(offer.getPrice()).loe(maxPrice)); + } + + return findPaginated(criteria, query, alias); + } +} From 54e8a7d4ac54d3bd6a719371753f06a9b11cec75 Mon Sep 17 00:00:00 2001 From: Malte Brunnlieb Date: Sun, 24 Jul 2016 14:49:53 +0530 Subject: [PATCH 17/18] removed client submodule as not interesting for the training so far --- .gitmodules | 3 --- samples/server/src/main/client | 1 - 2 files changed, 4 deletions(-) delete mode 160000 samples/server/src/main/client diff --git a/.gitmodules b/.gitmodules index 4a3839e11..c62f31ee0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "oasp4j-ide"] path = oasp4j-ide url = https://github.com/oasp/oasp4j-ide.git -[submodule "samples/server/src/main/client"] - path = samples/server/src/main/client - url = https://github.com/oasp/oasp4js.git diff --git a/samples/server/src/main/client b/samples/server/src/main/client deleted file mode 160000 index 87db7387d..000000000 --- a/samples/server/src/main/client +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 87db7387d99a604a70f9262e12ccc9f5c48efaa1 From 7ea2181e444039df4272c5935e46a6cbabe02950 Mon Sep 17 00:00:00 2001 From: Jorge Dacal Cantos <32701664+Jorge-Dacal@users.noreply.github.com> Date: Mon, 9 Jul 2018 14:32:19 +0200 Subject: [PATCH 18/18] Update LICENSE.txt For more information contact with Devonfw-Core-Team. --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index d64569567..fce5e4c57 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2015-2018 Capgemini SE. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.