mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-17 04:26:05 +00:00
* #2450 1. Refactored Layers Architecture to be a Spring boot app. 2. Changed the xml-based configuration to annotation-based. 3. Used spring's constructor injection to pass around needed objects. 4. Implemented deleteAll() methods for the CakeBakingServiceImpl to be used during testing 5. Implemented a CommandLineRunner to run the spring boot app. And others. * #2450 added the contents of the etc directory and a README.md * #2450 made corrections in response to the PR tests * #2450 made corrections in response to requested changes * #2450 made corrections in response to requested changes --------- Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
co-authored by
Ilkka Seppälä
parent
e40923d938
commit
edbb59a982
+9
-27
@@ -3,34 +3,31 @@ title: Layers
|
|||||||
category: Architectural
|
category: Architectural
|
||||||
language: en
|
language: en
|
||||||
tag:
|
tag:
|
||||||
- Decoupling
|
- Decoupling
|
||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
Layers is an architectural pattern where software responsibilities are divided among the different
|
Layers is an architectural pattern where software responsibilities are divided among the different
|
||||||
layers of the application.
|
layers of the application.
|
||||||
|
|
||||||
## Explanation
|
## Explanation
|
||||||
|
|
||||||
Real world example
|
Real world example
|
||||||
|
|
||||||
> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page
|
> Consider a website displaying decorated cakes for weddings and such. Instead of the web page
|
||||||
> directly reaching into the database, it relies on a service to deliver this information. The
|
> directly reaching into the database, it relies on a service to deliver this information. The
|
||||||
> service then queries the data layer to assimilate the needed information.
|
> service then queries the data layer to assimilate the needed information.
|
||||||
|
|
||||||
In plain words
|
In plain words
|
||||||
|
|
||||||
> With Layers architectural pattern different concerns reside on separate layers. View layer is
|
> With Layers architectural pattern different concerns reside on separate layers. View layer is
|
||||||
> interested only in rendering, service layer assembles the requested data from various sources, and
|
> interested only in rendering, service layer assembles the requested data from various sources, and
|
||||||
> data layer gets the bits from the data storage.
|
> data layer gets the bits from the data storage.
|
||||||
|
|
||||||
Wikipedia says
|
Wikipedia says
|
||||||
|
|
||||||
> In software engineering, multitier architecture (often referred to as n-tier architecture) or
|
> In software engineering, multitier architecture (often referred to as n-tier architecture) or
|
||||||
> multilayered architecture is a client–server architecture in which presentation, application
|
> multilayered architecture is a client–server architecture in which presentation, application
|
||||||
> processing, and data management functions are physically separated.
|
> processing, and data management functions are physically separated.
|
||||||
|
|
||||||
**Programmatic Example**
|
**Programmatic Example**
|
||||||
|
|
||||||
On the data layer, we keep our cake building blocks. `Cake` consist of layers and topping.
|
On the data layer, we keep our cake building blocks. `Cake` consist of layers and topping.
|
||||||
@@ -38,14 +35,11 @@ On the data layer, we keep our cake building blocks. `Cake` consist of layers an
|
|||||||
```java
|
```java
|
||||||
@Entity
|
@Entity
|
||||||
public class Cake {
|
public class Cake {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.REMOVE)
|
@OneToOne(cascade = CascadeType.REMOVE)
|
||||||
private CakeTopping topping;
|
private CakeTopping topping;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
||||||
private Set<CakeLayer> layers;
|
private Set<CakeLayer> layers;
|
||||||
}
|
}
|
||||||
@@ -55,17 +49,11 @@ The service layer offers `CakeBakingService` for easy access to different aspect
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
public interface CakeBakingService {
|
public interface CakeBakingService {
|
||||||
|
|
||||||
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
||||||
|
|
||||||
List<CakeInfo> getAllCakes();
|
List<CakeInfo> getAllCakes();
|
||||||
|
|
||||||
void saveNewTopping(CakeToppingInfo toppingInfo);
|
void saveNewTopping(CakeToppingInfo toppingInfo);
|
||||||
|
|
||||||
List<CakeToppingInfo> getAvailableToppings();
|
List<CakeToppingInfo> getAvailableToppings();
|
||||||
|
|
||||||
void saveNewLayer(CakeLayerInfo layerInfo);
|
void saveNewLayer(CakeLayerInfo layerInfo);
|
||||||
|
|
||||||
List<CakeLayerInfo> getAvailableLayers();
|
List<CakeLayerInfo> getAvailableLayers();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -74,20 +62,14 @@ On the top we have our `View` responsible of rendering the cakes.
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
public interface View {
|
public interface View {
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CakeViewImpl implements View {
|
public class CakeViewImpl implements View {
|
||||||
|
|
||||||
private final CakeBakingService cakeBakingService;
|
private final CakeBakingService cakeBakingService;
|
||||||
|
|
||||||
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
||||||
this.cakeBakingService = cakeBakingService;
|
this.cakeBakingService = cakeBakingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render() {
|
public void render() {
|
||||||
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
|
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
|
||||||
}
|
}
|
||||||
@@ -108,4 +90,4 @@ Use the Layers architecture when
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* [Pattern Oriented Software Architecture Volume 1: A System of Patterns](https://www.amazon.com/gp/product/0471958697/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471958697&linkCode=as2&tag=javadesignpat-20&linkId=e3f42d7a2a4cc8c619bbc0136b20dadb)
|
* [Pattern Oriented Software Architecture Volume 1: A System of Patterns](https://www.amazon.com/gp/product/0471958697/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471958697&linkCode=as2&tag=javadesignpat-20&linkId=e3f42d7a2a4cc8c619bbc0136b20dadb)
|
||||||
+239
-239
@@ -1,256 +1,256 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
||||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
|
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
|
||||||
<interface id="1" language="java" name="com.iluwatar.layers.dao.CakeDao" project="layers"
|
<interface id="1" language="java" name="com.iluwatar.layers.dao.CakeDao" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeDao.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeDao.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="289" y="916"/>
|
<position height="-1" width="-1" x="289" y="916"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</interface>
|
</interface>
|
||||||
<class id="2" language="java" name="com.iluwatar.layers.entity.CakeLayer" project="layers"
|
<class id="2" language="java" name="com.iluwatar.layers.entity.CakeLayer" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeLayer.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeLayer.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="1438" y="826"/>
|
<position height="-1" width="-1" x="1438" y="826"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="3" language="java" name="com.iluwatar.layers.view.CakeViewImpl" project="layers"
|
<class id="3" language="java" name="com.iluwatar.layers.view.CakeViewImpl" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="456" y="221"/>
|
<position height="-1" width="-1" x="456" y="221"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="4" language="java" name="com.iluwatar.layers.exception.CakeBakingException" project="layers"
|
<class id="4" language="java" name="com.iluwatar.layers.exception.CakeBakingException" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingException.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingException.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="143" y="502"/>
|
<position height="-1" width="-1" x="143" y="502"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="5" language="java" name="com.iluwatar.layers.service.CakeBakingServiceImpl" project="layers"
|
<class id="5" language="java" name="com.iluwatar.layers.service.CakeBakingServiceImpl" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="456" y="694"/>
|
<position height="-1" width="-1" x="456" y="694"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<interface id="6" language="java" name="com.iluwatar.layers.dao.CakeLayerDao" project="layers"
|
<interface id="6" language="java" name="com.iluwatar.layers.dao.CakeLayerDao" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeLayerDao.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeLayerDao.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="456" y="918"/>
|
<position height="-1" width="-1" x="456" y="918"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</interface>
|
</interface>
|
||||||
<interface id="7" language="java" name="com.iluwatar.layers.view.View" project="layers"
|
<interface id="7" language="java" name="com.iluwatar.layers.view.View" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/View.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/View.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="456" y="65"/>
|
<position height="-1" width="-1" x="456" y="65"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</interface>
|
</interface>
|
||||||
<class id="8" language="java" name="com.iluwatar.layers.dto.CakeToppingInfo" project="layers"
|
<class id="8" language="java" name="com.iluwatar.layers.dto.CakeToppingInfo" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="817" y="530"/>
|
<position height="-1" width="-1" x="817" y="530"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="9" language="java" name="com.iluwatar.layers.dto.CakeInfo" project="layers"
|
<class id="9" language="java" name="com.iluwatar.layers.dto.CakeInfo" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="883" y="265"/>
|
<position height="-1" width="-1" x="883" y="265"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<interface id="10" language="java" name="com.iluwatar.layers.dao.CakeToppingDao" project="layers"
|
<interface id="10" language="java" name="com.iluwatar.layers.dao.CakeToppingDao" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeToppingDao.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeToppingDao.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="633" y="918"/>
|
<position height="-1" width="-1" x="633" y="918"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</interface>
|
</interface>
|
||||||
<interface id="11" language="java" name="com.iluwatar.layers.service.CakeBakingService" project="layers"
|
<interface id="11" language="java" name="com.iluwatar.layers.service.CakeBakingService" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="456" y="431"/>
|
<position height="-1" width="-1" x="456" y="431"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</interface>
|
</interface>
|
||||||
<class id="12" language="java" name="com.iluwatar.layers.dto.CakeLayerInfo" project="layers"
|
<class id="12" language="java" name="com.iluwatar.layers.dto.CakeLayerInfo" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="1055" y="530"/>
|
<position height="-1" width="-1" x="1055" y="530"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="13" language="java" name="com.iluwatar.layers.entity.Cake" project="layers"
|
<class id="13" language="java" name="com.iluwatar.layers.entity.Cake" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/Cake.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/Cake.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="1160" y="826"/>
|
<position height="-1" width="-1" x="1160" y="826"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="14" language="java" name="com.iluwatar.layers.entity.CakeTopping" project="layers"
|
<class id="14" language="java" name="com.iluwatar.layers.entity.CakeTopping" project="layers"
|
||||||
file="/layers/src/main/java/com/iluwatar/layers/CakeTopping.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/layers/src/main/java/com/iluwatar/layers/CakeTopping.java" binary="false" corner="BOTTOM_RIGHT">
|
||||||
<position height="-1" width="-1" x="876" y="826"/>
|
<position height="-1" width="-1" x="876" y="826"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<association id="15">
|
<association id="15">
|
||||||
<end type="SOURCE" refId="9" navigable="false">
|
<end type="SOURCE" refId="9" navigable="false">
|
||||||
<attribute id="16" name="cakeToppingInfo"/>
|
<attribute id="16" name="cakeToppingInfo"/>
|
||||||
<multiplicity id="17" minimum="0" maximum="1"/>
|
<multiplicity id="17" minimum="0" maximum="1"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="8" navigable="true"/>
|
<end type="TARGET" refId="8" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<dependency id="18">
|
<dependency id="18">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="10"/>
|
<end type="TARGET" refId="10"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<association id="19">
|
<association id="19">
|
||||||
<end type="SOURCE" refId="13" navigable="false">
|
<end type="SOURCE" refId="13" navigable="false">
|
||||||
<attribute id="20" name="layers"/>
|
<attribute id="20" name="layers"/>
|
||||||
<multiplicity id="21" minimum="0" maximum="2147483647"/>
|
<multiplicity id="21" minimum="0" maximum="2147483647"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="2" navigable="true"/>
|
<end type="TARGET" refId="2" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<dependency id="22">
|
<dependency id="22">
|
||||||
<end type="SOURCE" refId="11"/>
|
<end type="SOURCE" refId="11"/>
|
||||||
<end type="TARGET" refId="4"/>
|
<end type="TARGET" refId="4"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<realization id="23">
|
<realization id="23">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="11"/>
|
<end type="TARGET" refId="11"/>
|
||||||
</realization>
|
</realization>
|
||||||
<association id="24">
|
<association id="24">
|
||||||
<end type="SOURCE" refId="13" navigable="false">
|
<end type="SOURCE" refId="13" navigable="false">
|
||||||
<attribute id="25" name="topping"/>
|
<attribute id="25" name="topping"/>
|
||||||
<multiplicity id="26" minimum="0" maximum="1"/>
|
<multiplicity id="26" minimum="0" maximum="1"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="14" navigable="true"/>
|
<end type="TARGET" refId="14" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<association id="27">
|
<association id="27">
|
||||||
<end type="SOURCE" refId="2" navigable="false">
|
<end type="SOURCE" refId="2" navigable="false">
|
||||||
<attribute id="28" name="cake"/>
|
<attribute id="28" name="cake"/>
|
||||||
<multiplicity id="29" minimum="0" maximum="1"/>
|
<multiplicity id="29" minimum="0" maximum="1"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="13" navigable="true"/>
|
<end type="TARGET" refId="13" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<dependency id="30">
|
<dependency id="30">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="14"/>
|
<end type="TARGET" refId="14"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="31">
|
<dependency id="31">
|
||||||
<end type="SOURCE" refId="11"/>
|
<end type="SOURCE" refId="11"/>
|
||||||
<end type="TARGET" refId="12"/>
|
<end type="TARGET" refId="12"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<association id="32">
|
<association id="32">
|
||||||
<end type="SOURCE" refId="3" navigable="false">
|
<end type="SOURCE" refId="3" navigable="false">
|
||||||
<attribute id="33" name="cakeBakingService"/>
|
<attribute id="33" name="cakeBakingService"/>
|
||||||
<multiplicity id="34" minimum="0" maximum="1"/>
|
<multiplicity id="34" minimum="0" maximum="1"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="11" navigable="true"/>
|
<end type="TARGET" refId="11" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<dependency id="35">
|
<dependency id="35">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="1"/>
|
<end type="TARGET" refId="1"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="36">
|
<dependency id="36">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="2"/>
|
<end type="TARGET" refId="2"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="37">
|
<dependency id="37">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="4"/>
|
<end type="TARGET" refId="4"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="38">
|
<dependency id="38">
|
||||||
<end type="SOURCE" refId="11"/>
|
<end type="SOURCE" refId="11"/>
|
||||||
<end type="TARGET" refId="8"/>
|
<end type="TARGET" refId="8"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<association id="39">
|
<association id="39">
|
||||||
<end type="SOURCE" refId="9" navigable="false">
|
<end type="SOURCE" refId="9" navigable="false">
|
||||||
<attribute id="40" name="cakeLayerInfos"/>
|
<attribute id="40" name="cakeLayerInfos"/>
|
||||||
<multiplicity id="41" minimum="0" maximum="2147483647"/>
|
<multiplicity id="41" minimum="0" maximum="2147483647"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="12" navigable="true"/>
|
<end type="TARGET" refId="12" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<realization id="42">
|
<realization id="42">
|
||||||
<end type="SOURCE" refId="3"/>
|
<end type="SOURCE" refId="3"/>
|
||||||
<end type="TARGET" refId="7"/>
|
<end type="TARGET" refId="7"/>
|
||||||
</realization>
|
</realization>
|
||||||
<dependency id="43">
|
<dependency id="43">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="12"/>
|
<end type="TARGET" refId="12"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="44">
|
<dependency id="44">
|
||||||
<end type="SOURCE" refId="11"/>
|
<end type="SOURCE" refId="11"/>
|
||||||
<end type="TARGET" refId="9"/>
|
<end type="TARGET" refId="9"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<association id="45">
|
<association id="45">
|
||||||
<end type="SOURCE" refId="14" navigable="false">
|
<end type="SOURCE" refId="14" navigable="false">
|
||||||
<attribute id="46" name="cake"/>
|
<attribute id="46" name="cake"/>
|
||||||
<multiplicity id="47" minimum="0" maximum="1"/>
|
<multiplicity id="47" minimum="0" maximum="1"/>
|
||||||
</end>
|
</end>
|
||||||
<end type="TARGET" refId="13" navigable="true"/>
|
<end type="TARGET" refId="13" navigable="true"/>
|
||||||
<display labels="true" multiplicity="true"/>
|
<display labels="true" multiplicity="true"/>
|
||||||
</association>
|
</association>
|
||||||
<dependency id="48">
|
<dependency id="48">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="6"/>
|
<end type="TARGET" refId="6"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="49">
|
<dependency id="49">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="8"/>
|
<end type="TARGET" refId="8"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="50">
|
<dependency id="50">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="9"/>
|
<end type="TARGET" refId="9"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency id="51">
|
<dependency id="51">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="13"/>
|
<end type="TARGET" refId="13"/>
|
||||||
</dependency>
|
</dependency>
|
||||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
|
<classifier-display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</classifier-display>
|
</classifier-display>
|
||||||
<association-display labels="true" multiplicity="true"/>
|
<association-display labels="true" multiplicity="true"/>
|
||||||
</class-diagram>
|
</class-diagram>
|
||||||
@@ -131,6 +131,6 @@ CakeViewImpl --> "-cakeBakingService" CakeBakingService
|
|||||||
App --> "-cakeBakingService" CakeBakingService
|
App --> "-cakeBakingService" CakeBakingService
|
||||||
Cake --> "-topping" CakeTopping
|
Cake --> "-topping" CakeTopping
|
||||||
CakeLayer --> "-cake" Cake
|
CakeLayer --> "-cake" Cake
|
||||||
CakeBakingServiceImpl ..|> CakeBakingService
|
CakeBakingServiceImpl ..|> CakeBakingService
|
||||||
CakeViewImpl ..|> View
|
CakeViewImpl ..|> View
|
||||||
@enduml
|
@enduml
|
||||||
+57
-64
@@ -1,11 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
|
||||||
The MIT License
|
The MIT License
|
||||||
Copyright © 2014-2022 Ilkka Seppälä
|
Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
@@ -22,67 +19,63 @@
|
|||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.-->
|
||||||
|
|
||||||
-->
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>layers</artifactId>
|
||||||
<version>1.26.0-SNAPSHOT</version>
|
<name>layers</name>
|
||||||
</parent>
|
<description>layers</description>
|
||||||
<groupId>com.iluwatar.layers</groupId>
|
<dependencies>
|
||||||
<artifactId>layers</artifactId>
|
<dependency>
|
||||||
<dependencies>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<dependency>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
<groupId>org.springframework.data</groupId>
|
</dependency>
|
||||||
<artifactId>spring-data-jpa</artifactId>
|
<dependency>
|
||||||
</dependency>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<dependency>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
<groupId>org.hibernate</groupId>
|
</dependency>
|
||||||
<artifactId>hibernate-core</artifactId>
|
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>com.h2database</groupId>
|
||||||
<groupId>javax.xml.bind</groupId>
|
<artifactId>h2</artifactId>
|
||||||
<artifactId>jaxb-api</artifactId>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-dbcp</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>commons-dbcp</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
<optional>true</optional>
|
||||||
<dependency>
|
</dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<dependency>
|
||||||
<artifactId>h2</artifactId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
</dependency>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<dependency>
|
<scope>test</scope>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
</dependency>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
</dependencies>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
<build>
|
||||||
<dependency>
|
<plugins>
|
||||||
<groupId>org.mockito</groupId>
|
<plugin>
|
||||||
<artifactId>mockito-core</artifactId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<scope>test</scope>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</dependency>
|
<configuration>
|
||||||
</dependencies>
|
<excludes>
|
||||||
<build>
|
<exclude>
|
||||||
<plugins>
|
<groupId>org.projectlombok</groupId>
|
||||||
<plugin>
|
<artifactId>lombok</artifactId>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
</exclude>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
</excludes>
|
||||||
<executions>
|
</configuration>
|
||||||
<execution>
|
</plugin>
|
||||||
<configuration>
|
</plugins>
|
||||||
<archive>
|
</build>
|
||||||
<manifest>
|
|
||||||
<mainClass>com.iluwatar.layers.app.App</mainClass>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.iluwatar.layers;
|
||||||
|
|
||||||
|
import dto.CakeInfo;
|
||||||
|
import dto.CakeLayerInfo;
|
||||||
|
import dto.CakeToppingInfo;
|
||||||
|
import exception.CakeBakingException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import service.CakeBakingService;
|
||||||
|
import view.CakeViewImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class Runner implements CommandLineRunner {
|
||||||
|
private final CakeBakingService cakeBakingService;
|
||||||
|
public static final String STRAWBERRY = "strawberry";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public Runner(CakeBakingService cakeBakingService) {
|
||||||
|
this.cakeBakingService = cakeBakingService;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void run(String... args) {
|
||||||
|
//initialize sample data
|
||||||
|
initializeData();
|
||||||
|
// create view and render it
|
||||||
|
var cakeView = new CakeViewImpl(cakeBakingService);
|
||||||
|
cakeView.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the example data.
|
||||||
|
*/
|
||||||
|
private void initializeData() {
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200));
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("banana", 900));
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950));
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("lemon", 950));
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("vanilla", 950));
|
||||||
|
cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950));
|
||||||
|
|
||||||
|
cakeBakingService.saveNewTopping(new CakeToppingInfo("candies", 350));
|
||||||
|
cakeBakingService.saveNewTopping(new CakeToppingInfo("cherry", 350));
|
||||||
|
|
||||||
|
var cake1 = new CakeInfo(new CakeToppingInfo("candies", 0), List.of(
|
||||||
|
new CakeLayerInfo("chocolate", 0),
|
||||||
|
new CakeLayerInfo("banana", 0),
|
||||||
|
new CakeLayerInfo(STRAWBERRY, 0)));
|
||||||
|
try {
|
||||||
|
cakeBakingService.bakeNewCake(cake1);
|
||||||
|
} catch (CakeBakingException e) {
|
||||||
|
LOGGER.error("Cake baking exception", e);
|
||||||
|
}
|
||||||
|
var cake2 = new CakeInfo(new CakeToppingInfo("cherry", 0), List.of(
|
||||||
|
new CakeLayerInfo("vanilla", 0),
|
||||||
|
new CakeLayerInfo("lemon", 0),
|
||||||
|
new CakeLayerInfo(STRAWBERRY, 0)));
|
||||||
|
try {
|
||||||
|
cakeBakingService.bakeNewCake(cake2);
|
||||||
|
} catch (CakeBakingException e) {
|
||||||
|
LOGGER.error("Cake baking exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2022 Ilkka Seppälä
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package com.iluwatar.layers.app;
|
|
||||||
|
|
||||||
import com.iluwatar.layers.dao.CakeDao;
|
|
||||||
import com.iluwatar.layers.dao.CakeLayerDao;
|
|
||||||
import com.iluwatar.layers.dao.CakeToppingDao;
|
|
||||||
import com.iluwatar.layers.dto.CakeInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeLayerInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeToppingInfo;
|
|
||||||
import com.iluwatar.layers.entity.Cake;
|
|
||||||
import com.iluwatar.layers.entity.CakeLayer;
|
|
||||||
import com.iluwatar.layers.entity.CakeTopping;
|
|
||||||
import com.iluwatar.layers.exception.CakeBakingException;
|
|
||||||
import com.iluwatar.layers.service.CakeBakingService;
|
|
||||||
import com.iluwatar.layers.service.CakeBakingServiceImpl;
|
|
||||||
import com.iluwatar.layers.view.CakeViewImpl;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Layers is an architectural style where software responsibilities are divided among the
|
|
||||||
* different layers of the application.
|
|
||||||
*
|
|
||||||
* <p>This example demonstrates a traditional 3-layer architecture consisting of data access
|
|
||||||
* layer, business layer and presentation layer.
|
|
||||||
*
|
|
||||||
* <p>The data access layer is formed of Spring Data repositories <code>CakeDao</code>,
|
|
||||||
* <code>CakeToppingDao</code> and <code>CakeLayerDao</code>. The repositories can be used
|
|
||||||
* for CRUD operations on cakes, cake toppings and cake layers respectively.
|
|
||||||
*
|
|
||||||
* <p>The business layer is built on top of the data access layer. <code>CakeBakingService</code>
|
|
||||||
* offers methods to retrieve available cake toppings and cake layers and baked cakes. Also the
|
|
||||||
* service is used to create new cakes out of cake toppings and cake layers.
|
|
||||||
*
|
|
||||||
* <p>The presentation layer is built on the business layer and in this example it simply lists
|
|
||||||
* the cakes that have been baked.
|
|
||||||
*
|
|
||||||
* <p>We have applied so called strict layering which means that the layers can only access the
|
|
||||||
* classes directly beneath them. This leads the solution to create an additional set of DTOs
|
|
||||||
* ( <code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) to translate
|
|
||||||
* data between layers. In other words, <code>CakeBakingService</code> cannot return entities
|
|
||||||
* ( <code>Cake</code>, <code>CakeTopping</code>, <code>CakeLayer</code>) directly since these
|
|
||||||
* reside on data access layer but instead translates these into business layer DTOs
|
|
||||||
* (<code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) and returns
|
|
||||||
* them instead. This way the presentation layer does not have any knowledge of other layers than
|
|
||||||
* the business layer and thus is not affected by changes to them.
|
|
||||||
*
|
|
||||||
* @see Cake
|
|
||||||
* @see CakeTopping
|
|
||||||
* @see CakeLayer
|
|
||||||
* @see CakeDao
|
|
||||||
* @see CakeToppingDao
|
|
||||||
* @see CakeLayerDao
|
|
||||||
* @see CakeBakingService
|
|
||||||
* @see CakeInfo
|
|
||||||
* @see CakeToppingInfo
|
|
||||||
* @see CakeLayerInfo
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class App {
|
|
||||||
|
|
||||||
private static final CakeBakingService cakeBakingService = new CakeBakingServiceImpl();
|
|
||||||
public static final String STRAWBERRY = "strawberry";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Application entry point.
|
|
||||||
*
|
|
||||||
* @param args Command line parameters
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// initialize example data
|
|
||||||
initializeData(cakeBakingService);
|
|
||||||
|
|
||||||
// create view and render it
|
|
||||||
var cakeView = new CakeViewImpl(cakeBakingService);
|
|
||||||
cakeView.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the example data.
|
|
||||||
*/
|
|
||||||
private static void initializeData(CakeBakingService cakeBakingService) {
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200));
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo("banana", 900));
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950));
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo("lemon", 950));
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo("vanilla", 950));
|
|
||||||
cakeBakingService.saveNewLayer(new CakeLayerInfo(STRAWBERRY, 950));
|
|
||||||
|
|
||||||
cakeBakingService.saveNewTopping(new CakeToppingInfo("candies", 350));
|
|
||||||
cakeBakingService.saveNewTopping(new CakeToppingInfo("cherry", 350));
|
|
||||||
|
|
||||||
var cake1 = new CakeInfo(new CakeToppingInfo("candies", 0), List.of(
|
|
||||||
new CakeLayerInfo("chocolate", 0),
|
|
||||||
new CakeLayerInfo("banana", 0),
|
|
||||||
new CakeLayerInfo(STRAWBERRY, 0)));
|
|
||||||
try {
|
|
||||||
cakeBakingService.bakeNewCake(cake1);
|
|
||||||
} catch (CakeBakingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
var cake2 = new CakeInfo(new CakeToppingInfo("cherry", 0), List.of(
|
|
||||||
new CakeLayerInfo("vanilla", 0),
|
|
||||||
new CakeLayerInfo("lemon", 0),
|
|
||||||
new CakeLayerInfo(STRAWBERRY, 0)));
|
|
||||||
try {
|
|
||||||
cakeBakingService.bakeNewCake(cake2);
|
|
||||||
} catch (CakeBakingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.iluwatar.layers.app;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableJpaRepositories(basePackages = "dao")
|
||||||
|
@EntityScan(basePackages = "entity")
|
||||||
|
@ComponentScan(basePackages = {"com.iluwatar.layers", "service", "dto", "exception", "view" ,"dao"})
|
||||||
|
public class LayersApp {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(LayersApp.class, args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2022 Ilkka Seppälä
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package com.iluwatar.layers.entity;
|
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.ManyToOne;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CakeLayer entity.
|
|
||||||
*/
|
|
||||||
@Entity
|
|
||||||
public class CakeLayer {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private int calories;
|
|
||||||
|
|
||||||
@ManyToOne(cascade = CascadeType.ALL)
|
|
||||||
private Cake cake;
|
|
||||||
|
|
||||||
public CakeLayer() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public CakeLayer(String name, int calories) {
|
|
||||||
this.setName(name);
|
|
||||||
this.setCalories(calories);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCalories() {
|
|
||||||
return calories;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCalories(int calories) {
|
|
||||||
this.calories = calories;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("id=%s name=%s calories=%d", id, name, calories);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cake getCake() {
|
|
||||||
return cake;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCake(Cake cake) {
|
|
||||||
this.cake = cake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2022 Ilkka Seppälä
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package com.iluwatar.layers.entity;
|
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.OneToOne;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CakeTopping entity.
|
|
||||||
*/
|
|
||||||
@Entity
|
|
||||||
public class CakeTopping {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private int calories;
|
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.ALL)
|
|
||||||
private Cake cake;
|
|
||||||
|
|
||||||
public CakeTopping() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public CakeTopping(String name, int calories) {
|
|
||||||
this.setName(name);
|
|
||||||
this.setCalories(calories);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCalories() {
|
|
||||||
return calories;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCalories(int calories) {
|
|
||||||
this.calories = calories;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("id=%s name=%s calories=%d", id, name, calories);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cake getCake() {
|
|
||||||
return cake;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCake(Cake cake) {
|
|
||||||
this.cake = cake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
/*
|
|
||||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
|
||||||
*
|
|
||||||
* The MIT License
|
|
||||||
* Copyright © 2014-2022 Ilkka Seppälä
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package com.iluwatar.layers.service;
|
|
||||||
|
|
||||||
import com.iluwatar.layers.dao.CakeDao;
|
|
||||||
import com.iluwatar.layers.dao.CakeLayerDao;
|
|
||||||
import com.iluwatar.layers.dao.CakeToppingDao;
|
|
||||||
import com.iluwatar.layers.dto.CakeInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeLayerInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeToppingInfo;
|
|
||||||
import com.iluwatar.layers.entity.Cake;
|
|
||||||
import com.iluwatar.layers.entity.CakeLayer;
|
|
||||||
import com.iluwatar.layers.entity.CakeTopping;
|
|
||||||
import com.iluwatar.layers.exception.CakeBakingException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.springframework.context.support.AbstractApplicationContext;
|
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of CakeBakingService.
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
public class CakeBakingServiceImpl implements CakeBakingService {
|
|
||||||
|
|
||||||
private final AbstractApplicationContext context;
|
|
||||||
|
|
||||||
public CakeBakingServiceImpl() {
|
|
||||||
this.context = new ClassPathXmlApplicationContext("applicationContext.xml");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException {
|
|
||||||
var allToppings = getAvailableToppingEntities();
|
|
||||||
var matchingToppings =
|
|
||||||
allToppings.stream().filter(t -> t.getName().equals(cakeInfo.cakeToppingInfo.name))
|
|
||||||
.toList();
|
|
||||||
if (matchingToppings.isEmpty()) {
|
|
||||||
throw new CakeBakingException(String.format("Topping %s is not available",
|
|
||||||
cakeInfo.cakeToppingInfo.name));
|
|
||||||
}
|
|
||||||
var allLayers = getAvailableLayerEntities();
|
|
||||||
Set<CakeLayer> foundLayers = new HashSet<>();
|
|
||||||
for (var info : cakeInfo.cakeLayerInfos) {
|
|
||||||
var found = allLayers.stream().filter(layer -> layer.getName().equals(info.name)).findFirst();
|
|
||||||
if (found.isEmpty()) {
|
|
||||||
throw new CakeBakingException(String.format("Layer %s is not available", info.name));
|
|
||||||
} else {
|
|
||||||
foundLayers.add(found.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var toppingBean = context.getBean(CakeToppingDao.class);
|
|
||||||
var topping = toppingBean.findById(matchingToppings.iterator().next().getId());
|
|
||||||
var cakeBean = context.getBean(CakeDao.class);
|
|
||||||
if (topping.isPresent()) {
|
|
||||||
var cake = new Cake();
|
|
||||||
cake.setTopping(topping.get());
|
|
||||||
cake.setLayers(foundLayers);
|
|
||||||
cakeBean.save(cake);
|
|
||||||
topping.get().setCake(cake);
|
|
||||||
toppingBean.save(topping.get());
|
|
||||||
var layerBean = context.getBean(CakeLayerDao.class);
|
|
||||||
for (var layer : foundLayers) {
|
|
||||||
layer.setCake(cake);
|
|
||||||
layerBean.save(layer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CakeBakingException(String.format("Topping %s is not available",
|
|
||||||
cakeInfo.cakeToppingInfo.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveNewTopping(CakeToppingInfo toppingInfo) {
|
|
||||||
var bean = context.getBean(CakeToppingDao.class);
|
|
||||||
bean.save(new CakeTopping(toppingInfo.name, toppingInfo.calories));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveNewLayer(CakeLayerInfo layerInfo) {
|
|
||||||
var bean = context.getBean(CakeLayerDao.class);
|
|
||||||
bean.save(new CakeLayer(layerInfo.name, layerInfo.calories));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CakeTopping> getAvailableToppingEntities() {
|
|
||||||
var bean = context.getBean(CakeToppingDao.class);
|
|
||||||
List<CakeTopping> result = new ArrayList<>();
|
|
||||||
for (CakeTopping topping : bean.findAll()) {
|
|
||||||
if (topping.getCake() == null) {
|
|
||||||
result.add(topping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CakeToppingInfo> getAvailableToppings() {
|
|
||||||
var bean = context.getBean(CakeToppingDao.class);
|
|
||||||
List<CakeToppingInfo> result = new ArrayList<>();
|
|
||||||
for (CakeTopping next : bean.findAll()) {
|
|
||||||
if (next.getCake() == null) {
|
|
||||||
result.add(new CakeToppingInfo(next.getId(), next.getName(), next.getCalories()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CakeLayer> getAvailableLayerEntities() {
|
|
||||||
var bean = context.getBean(CakeLayerDao.class);
|
|
||||||
List<CakeLayer> result = new ArrayList<>();
|
|
||||||
for (CakeLayer next : bean.findAll()) {
|
|
||||||
if (next.getCake() == null) {
|
|
||||||
result.add(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CakeLayerInfo> getAvailableLayers() {
|
|
||||||
var bean = context.getBean(CakeLayerDao.class);
|
|
||||||
List<CakeLayerInfo> result = new ArrayList<>();
|
|
||||||
for (CakeLayer next : bean.findAll()) {
|
|
||||||
if (next.getCake() == null) {
|
|
||||||
result.add(new CakeLayerInfo(next.getId(), next.getName(), next.getCalories()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CakeInfo> getAllCakes() {
|
|
||||||
var cakeBean = context.getBean(CakeDao.class);
|
|
||||||
List<CakeInfo> result = new ArrayList<>();
|
|
||||||
for (Cake cake : cakeBean.findAll()) {
|
|
||||||
var cakeToppingInfo =
|
|
||||||
new CakeToppingInfo(cake.getTopping().getId(), cake.getTopping().getName(), cake
|
|
||||||
.getTopping().getCalories());
|
|
||||||
List<CakeLayerInfo> cakeLayerInfos = new ArrayList<>();
|
|
||||||
for (var layer : cake.getLayers()) {
|
|
||||||
cakeLayerInfos.add(new CakeLayerInfo(layer.getId(), layer.getName(), layer.getCalories()));
|
|
||||||
}
|
|
||||||
var cakeInfo = new CakeInfo(cake.getId(), cakeToppingInfo, cakeLayerInfos);
|
|
||||||
result.add(cakeInfo);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-6
@@ -22,16 +22,14 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dao;
|
package dao;
|
||||||
|
|
||||||
import com.iluwatar.layers.entity.Cake;
|
import entity.Cake;
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRUD repository for cakes.
|
* CRUD repository for cakes.
|
||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public interface CakeDao extends CrudRepository<Cake, Long> {
|
public interface CakeDao extends JpaRepository<Cake, Long> {}
|
||||||
|
|
||||||
}
|
|
||||||
+4
-4
@@ -22,16 +22,16 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dao;
|
package dao;
|
||||||
|
|
||||||
import com.iluwatar.layers.entity.CakeLayer;
|
import entity.CakeLayer;
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRUD repository for cake layers.
|
* CRUD repository for cake layers.
|
||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public interface CakeLayerDao extends CrudRepository<CakeLayer, Long> {
|
public interface CakeLayerDao extends JpaRepository<CakeLayer, Long> {
|
||||||
|
|
||||||
}
|
}
|
||||||
+6
-4
@@ -22,16 +22,18 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dao;
|
package dao;
|
||||||
|
|
||||||
import com.iluwatar.layers.entity.CakeTopping;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
import entity.CakeTopping;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRUD repository cake toppings.
|
* CRUD repository cake toppings.
|
||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public interface CakeToppingDao extends CrudRepository<CakeTopping, Long> {
|
public interface CakeToppingDao extends JpaRepository<CakeTopping, Long> {
|
||||||
|
|
||||||
}
|
}
|
||||||
+33
-33
@@ -22,7 +22,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dto;
|
package dto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -32,40 +32,40 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public class CakeInfo {
|
public class CakeInfo {
|
||||||
|
|
||||||
public final Optional<Long> id;
|
public final Optional<Long> id;
|
||||||
public final CakeToppingInfo cakeToppingInfo;
|
public final CakeToppingInfo cakeToppingInfo;
|
||||||
public final List<CakeLayerInfo> cakeLayerInfos;
|
public final List<CakeLayerInfo> cakeLayerInfos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||||
this.id = Optional.of(id);
|
this.id = Optional.of(id);
|
||||||
this.cakeToppingInfo = cakeToppingInfo;
|
this.cakeToppingInfo = cakeToppingInfo;
|
||||||
this.cakeLayerInfos = cakeLayerInfos;
|
this.cakeLayerInfos = cakeLayerInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||||
this.id = Optional.empty();
|
this.id = Optional.empty();
|
||||||
this.cakeToppingInfo = cakeToppingInfo;
|
this.cakeToppingInfo = cakeToppingInfo;
|
||||||
this.cakeLayerInfos = cakeLayerInfos;
|
this.cakeLayerInfos = cakeLayerInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate calories.
|
* Calculate calories.
|
||||||
*/
|
*/
|
||||||
public int calculateTotalCalories() {
|
public int calculateTotalCalories() {
|
||||||
var total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
|
var total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
|
||||||
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
|
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.orElse(-1L),
|
return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.orElse(-1L),
|
||||||
cakeToppingInfo, cakeLayerInfos, calculateTotalCalories());
|
cakeToppingInfo, cakeLayerInfos, calculateTotalCalories());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
-24
@@ -22,7 +22,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dto;
|
package dto;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -31,30 +31,30 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public class CakeLayerInfo {
|
public class CakeLayerInfo {
|
||||||
|
|
||||||
public final Optional<Long> id;
|
public final Optional<Long> id;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final int calories;
|
public final int calories;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeLayerInfo(Long id, String name, int calories) {
|
public CakeLayerInfo(Long id, String name, int calories) {
|
||||||
this.id = Optional.of(id);
|
this.id = Optional.of(id);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.calories = calories;
|
this.calories = calories;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeLayerInfo(String name, int calories) {
|
public CakeLayerInfo(String name, int calories) {
|
||||||
this.id = Optional.empty();
|
this.id = Optional.empty();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.calories = calories;
|
this.calories = calories;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("CakeLayerInfo id=%d name=%s calories=%d", id.orElse(-1L), name, calories);
|
return String.format("CakeLayerInfo id=%d name=%s calories=%d", id.orElse(-1L), name, calories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+26
-25
@@ -22,7 +22,8 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.dto;
|
package dto;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -31,31 +32,31 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public class CakeToppingInfo {
|
public class CakeToppingInfo {
|
||||||
|
|
||||||
public final Optional<Long> id;
|
public final Optional<Long> id;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final int calories;
|
public final int calories;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeToppingInfo(Long id, String name, int calories) {
|
public CakeToppingInfo(Long id, String name, int calories) {
|
||||||
this.id = Optional.of(id);
|
this.id = Optional.of(id);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.calories = calories;
|
this.calories = calories;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CakeToppingInfo(String name, int calories) {
|
public CakeToppingInfo(String name, int calories) {
|
||||||
this.id = Optional.empty();
|
this.id = Optional.empty();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.calories = calories;
|
this.calories = calories;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("CakeToppingInfo id=%d name=%s calories=%d",
|
return String.format("CakeToppingInfo id=%d name=%s calories=%d",
|
||||||
id.orElse(-1L), name, calories);
|
id.orElse(-1L), name, calories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+43
-43
@@ -22,17 +22,17 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.entity;
|
package entity;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.CascadeType;
|
import jakarta.persistence.Entity;
|
||||||
import javax.persistence.Entity;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import javax.persistence.FetchType;
|
import jakarta.persistence.Id;
|
||||||
import javax.persistence.GeneratedValue;
|
import jakarta.persistence.OneToMany;
|
||||||
import javax.persistence.Id;
|
import jakarta.persistence.OneToOne;
|
||||||
import javax.persistence.OneToMany;
|
import jakarta.persistence.CascadeType;
|
||||||
import javax.persistence.OneToOne;
|
import jakarta.persistence.FetchType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cake entity.
|
* Cake entity.
|
||||||
@@ -40,50 +40,50 @@ import javax.persistence.OneToOne;
|
|||||||
@Entity
|
@Entity
|
||||||
public class Cake {
|
public class Cake {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.REMOVE)
|
@OneToOne(cascade = CascadeType.REMOVE)
|
||||||
private CakeTopping topping;
|
private CakeTopping topping;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
||||||
private Set<CakeLayer> layers;
|
private Set<CakeLayer> layers;
|
||||||
|
|
||||||
public Cake() {
|
public Cake() {
|
||||||
setLayers(new HashSet<>());
|
setLayers(new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CakeTopping getTopping() {
|
public CakeTopping getTopping() {
|
||||||
return topping;
|
return topping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTopping(CakeTopping topping) {
|
public void setTopping(CakeTopping topping) {
|
||||||
this.topping = topping;
|
this.topping = topping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<CakeLayer> getLayers() {
|
public Set<CakeLayer> getLayers() {
|
||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLayers(Set<CakeLayer> layers) {
|
public void setLayers(Set<CakeLayer> layers) {
|
||||||
this.layers = layers;
|
this.layers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLayer(CakeLayer layer) {
|
public void addLayer(CakeLayer layer) {
|
||||||
this.layers.add(layer);
|
this.layers.add(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("id=%s topping=%s layers=%s", id, topping, layers.toString());
|
return String.format("id=%s topping=%s layers=%s", id, topping, layers.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+32
-11
@@ -22,21 +22,42 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.app;
|
package entity;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* CakeLayer entity.
|
||||||
* Application test
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
class AppTest {
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class CakeLayer {
|
||||||
|
|
||||||
@Test
|
@Id
|
||||||
void shouldExecuteApplicationWithoutException() {
|
@GeneratedValue
|
||||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
private Long id;
|
||||||
}
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int calories;
|
||||||
|
|
||||||
|
@ManyToOne(cascade = CascadeType.ALL)
|
||||||
|
private Cake cake;
|
||||||
|
|
||||||
|
public CakeLayer(String name, int calories) {
|
||||||
|
this.setName(name);
|
||||||
|
this.setCalories(calories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("id=%s name=%s calories=%d", id, name, calories);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CakeTopping entity.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class CakeTopping {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int calories;
|
||||||
|
|
||||||
|
@OneToOne(cascade = CascadeType.ALL)
|
||||||
|
private Cake cake;
|
||||||
|
|
||||||
|
public CakeTopping(String name, int calories) {
|
||||||
|
this.setName(name);
|
||||||
|
this.setCalories(calories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("id=%s name=%s calories=%d", id, name, calories);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+10
-7
@@ -22,19 +22,22 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.exception;
|
package exception;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom exception used in cake baking.
|
* Custom exception used in cake baking.
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class CakeBakingException extends Exception {
|
public class CakeBakingException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public CakeBakingException() {
|
public CakeBakingException() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CakeBakingException(String message) {
|
public CakeBakingException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+39
-29
@@ -22,46 +22,56 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.service;
|
package service;
|
||||||
|
|
||||||
|
import dto.CakeInfo;
|
||||||
|
import dto.CakeLayerInfo;
|
||||||
|
import dto.CakeToppingInfo;
|
||||||
|
import exception.CakeBakingException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.iluwatar.layers.dto.CakeInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeLayerInfo;
|
|
||||||
import com.iluwatar.layers.dto.CakeToppingInfo;
|
|
||||||
import com.iluwatar.layers.exception.CakeBakingException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for cake baking operations.
|
* Service for cake baking operations.
|
||||||
*/
|
*/
|
||||||
|
@Service
|
||||||
public interface CakeBakingService {
|
public interface CakeBakingService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bakes new cake according to parameters.
|
* Bakes new cake according to parameters.
|
||||||
*/
|
*/
|
||||||
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all cakes.
|
* Get all cakes.
|
||||||
*/
|
*/
|
||||||
List<CakeInfo> getAllCakes();
|
List<CakeInfo> getAllCakes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store new cake topping.
|
* Store new cake topping.
|
||||||
*/
|
*/
|
||||||
void saveNewTopping(CakeToppingInfo toppingInfo);
|
void saveNewTopping(CakeToppingInfo toppingInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get available cake toppings.
|
* Get available cake toppings.
|
||||||
*/
|
*/
|
||||||
List<CakeToppingInfo> getAvailableToppings();
|
List<CakeToppingInfo> getAvailableToppings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new cake layer.
|
* Add new cake layer.
|
||||||
*/
|
*/
|
||||||
void saveNewLayer(CakeLayerInfo layerInfo);
|
void saveNewLayer(CakeLayerInfo layerInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get available cake layers.
|
||||||
|
*/
|
||||||
|
List<CakeLayerInfo> getAvailableLayers();
|
||||||
|
|
||||||
|
void deleteAllCakes();
|
||||||
|
|
||||||
|
void deleteAllLayers();
|
||||||
|
|
||||||
|
void deleteAllToppings();
|
||||||
|
|
||||||
/**
|
|
||||||
* Get available cake layers.
|
|
||||||
*/
|
|
||||||
List<CakeLayerInfo> getAvailableLayers();
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package service;
|
||||||
|
|
||||||
|
import dao.CakeDao;
|
||||||
|
import dao.CakeLayerDao;
|
||||||
|
import dao.CakeToppingDao;
|
||||||
|
import dto.CakeInfo;
|
||||||
|
import dto.CakeLayerInfo;
|
||||||
|
import dto.CakeToppingInfo;
|
||||||
|
import entity.Cake;
|
||||||
|
import entity.CakeLayer;
|
||||||
|
import entity.CakeTopping;
|
||||||
|
import exception.CakeBakingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of CakeBakingService.
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class CakeBakingServiceImpl implements CakeBakingService {
|
||||||
|
|
||||||
|
private final CakeDao cakeDao;
|
||||||
|
private final CakeLayerDao cakeLayerDao;
|
||||||
|
private final CakeToppingDao cakeToppingDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public CakeBakingServiceImpl(CakeDao cakeDao, CakeLayerDao cakeLayerDao, CakeToppingDao cakeToppingDao) {
|
||||||
|
this.cakeDao = cakeDao;
|
||||||
|
this.cakeLayerDao = cakeLayerDao;
|
||||||
|
this.cakeToppingDao = cakeToppingDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException {
|
||||||
|
var allToppings = getAvailableToppingEntities();
|
||||||
|
var matchingToppings =
|
||||||
|
allToppings.stream().filter(t -> t.getName().equals(cakeInfo.cakeToppingInfo.name))
|
||||||
|
.toList();
|
||||||
|
if (matchingToppings.isEmpty()) {
|
||||||
|
throw new CakeBakingException(String.format("Topping %s is not available",
|
||||||
|
cakeInfo.cakeToppingInfo.name));
|
||||||
|
}
|
||||||
|
var allLayers = getAvailableLayerEntities();
|
||||||
|
Set<CakeLayer> foundLayers = new HashSet<>();
|
||||||
|
for (var info : cakeInfo.cakeLayerInfos) {
|
||||||
|
var found = allLayers.stream().filter(layer -> layer.getName().equals(info.name)).findFirst();
|
||||||
|
if (found.isEmpty()) {
|
||||||
|
throw new CakeBakingException(String.format("Layer %s is not available", info.name));
|
||||||
|
} else {
|
||||||
|
foundLayers.add(found.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var topping = cakeToppingDao.findById(matchingToppings.iterator().next().getId());
|
||||||
|
if (topping.isPresent()) {
|
||||||
|
var cake = new Cake();
|
||||||
|
cake.setTopping(topping.get());
|
||||||
|
cake.setLayers(foundLayers);
|
||||||
|
cakeDao.save(cake);
|
||||||
|
topping.get().setCake(cake);
|
||||||
|
cakeToppingDao.save(topping.get());
|
||||||
|
Set<CakeLayer> foundLayersToUpdate = new HashSet<>(foundLayers); // copy set to avoid a ConcurrentModificationException
|
||||||
|
|
||||||
|
for (var layer : foundLayersToUpdate) {
|
||||||
|
layer.setCake(cake);
|
||||||
|
cakeLayerDao.save(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new CakeBakingException(String.format("Topping %s is not available",
|
||||||
|
cakeInfo.cakeToppingInfo.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveNewTopping(CakeToppingInfo toppingInfo) {
|
||||||
|
cakeToppingDao.save(new CakeTopping(toppingInfo.name, toppingInfo.calories));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveNewLayer(CakeLayerInfo layerInfo) {
|
||||||
|
cakeLayerDao.save(new CakeLayer(layerInfo.name, layerInfo.calories));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CakeTopping> getAvailableToppingEntities() {
|
||||||
|
List<CakeTopping> result = new ArrayList<>();
|
||||||
|
for (CakeTopping topping : cakeToppingDao.findAll()) {
|
||||||
|
if (topping.getCake() == null) {
|
||||||
|
result.add(topping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CakeToppingInfo> getAvailableToppings() {
|
||||||
|
List<CakeToppingInfo> result = new ArrayList<>();
|
||||||
|
for (CakeTopping next : cakeToppingDao.findAll()) {
|
||||||
|
if (next.getCake() == null) {
|
||||||
|
result.add(new CakeToppingInfo(next.getId(), next.getName(), next.getCalories()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CakeLayer> getAvailableLayerEntities() {
|
||||||
|
List<CakeLayer> result = new ArrayList<>();
|
||||||
|
for (CakeLayer next : cakeLayerDao.findAll()) {
|
||||||
|
if (next.getCake() == null) {
|
||||||
|
result.add(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CakeLayerInfo> getAvailableLayers() {
|
||||||
|
List<CakeLayerInfo> result = new ArrayList<>();
|
||||||
|
for (CakeLayer next : cakeLayerDao.findAll()) {
|
||||||
|
if (next.getCake() == null) {
|
||||||
|
result.add(new CakeLayerInfo(next.getId(), next.getName(), next.getCalories()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAllCakes() {
|
||||||
|
cakeDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAllLayers() {
|
||||||
|
cakeLayerDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAllToppings() {
|
||||||
|
cakeToppingDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CakeInfo> getAllCakes() {
|
||||||
|
List<CakeInfo> result = new ArrayList<>();
|
||||||
|
for (Cake cake : cakeDao.findAll()) {
|
||||||
|
var cakeToppingInfo =
|
||||||
|
new CakeToppingInfo(cake.getTopping().getId(), cake.getTopping().getName(), cake
|
||||||
|
.getTopping().getCalories());
|
||||||
|
List<CakeLayerInfo> cakeLayerInfos = new ArrayList<>();
|
||||||
|
for (var layer : cake.getLayers()) {
|
||||||
|
cakeLayerInfos.add(new CakeLayerInfo(layer.getId(), layer.getName(), layer.getCalories()));
|
||||||
|
}
|
||||||
|
var cakeInfo = new CakeInfo(cake.getId(), cakeToppingInfo, cakeLayerInfos);
|
||||||
|
result.add(cakeInfo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-11
@@ -22,24 +22,26 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.view;
|
package view;
|
||||||
|
|
||||||
import com.iluwatar.layers.service.CakeBakingService;
|
import org.slf4j.Logger;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import service.CakeBakingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View implementation for displaying cakes.
|
* View implementation for displaying cakes.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
public class CakeViewImpl implements View {
|
public class CakeViewImpl implements View {
|
||||||
|
|
||||||
private final CakeBakingService cakeBakingService;
|
private final CakeBakingService cakeBakingService;
|
||||||
|
|
||||||
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
|
||||||
this.cakeBakingService = cakeBakingService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render() {
|
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
||||||
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
|
this.cakeBakingService = cakeBakingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void render() {
|
||||||
|
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -22,13 +22,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.iluwatar.layers.view;
|
package view;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View interface.
|
* View interface.
|
||||||
*/
|
*/
|
||||||
public interface View {
|
public interface View {
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
}
|
}
|
||||||
+26
-26
@@ -24,30 +24,30 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<configuration>
|
<configuration>
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
<file>layers.log</file>
|
<file>layers.log</file>
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
<fileNamePattern>layers-%d.log</fileNamePattern>
|
<fileNamePattern>layers-%d.log</fileNamePattern>
|
||||||
<maxHistory>5</maxHistory>
|
<maxHistory>5</maxHistory>
|
||||||
</rollingPolicy>
|
</rollingPolicy>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%-5p [%d{ISO8601,UTC}] %c: %m%n</pattern>
|
<pattern>%-5p [%d{ISO8601,UTC}] %c: %m%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%-5p [%d{ISO8601,UTC}] %c: %m%n</pattern>
|
<pattern>%-5p [%d{ISO8601,UTC}] %c: %m%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
<logger name="com.iluwatar" additivity="false">
|
<logger name="com.iluwatar" additivity="false">
|
||||||
<level value="DEBUG" />
|
<level value="DEBUG" />
|
||||||
<appender-ref ref="FILE" />
|
<appender-ref ref="FILE" />
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="org.hibernate" additivity="false">
|
<logger name="org.hibernate" additivity="false">
|
||||||
<level value="ERROR" />
|
<level value="ERROR" />
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</logger>
|
</logger>
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</root>
|
</root>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
Copyright © 2014-2021 Ilkka Seppälä
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
|
|
||||||
<persistence-unit name="jpaData" />
|
|
||||||
</persistence>
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
spring.main.web-application-type=none
|
||||||
|
|
||||||
|
#datasource settings
|
||||||
|
spring.datasource.url=jdbc:h2:~/databases/cake
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=sa
|
||||||
|
|
||||||
|
#data settings
|
||||||
|
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||||
|
spring.jpa.hibernate.ddl-auto=create-drop
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
The MIT License
|
|
||||||
Copyright © 2014-2021 Ilkka Seppälä
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
|
|
||||||
<jpa:repositories base-package="com.iluwatar" />
|
|
||||||
<tx:annotation-driven transaction-manager="transactionManager" />
|
|
||||||
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
|
|
||||||
<property name="entityManagerFactory" ref="entityManagerFactory" />
|
|
||||||
</bean>
|
|
||||||
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
|
|
||||||
<property name="driverClassName" value="org.h2.Driver" />
|
|
||||||
<property name="url" value="jdbc:h2:~/databases/cake" />
|
|
||||||
<property name="username" value="sa" />
|
|
||||||
<property name="password" value="sa" />
|
|
||||||
</bean>
|
|
||||||
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
|
||||||
<property name="dataSource" ref="dataSource" />
|
|
||||||
<property name="packagesToScan" value="com.iluwatar" />
|
|
||||||
<property name="persistenceProvider">
|
|
||||||
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
|
|
||||||
</property>
|
|
||||||
<property name="jpaProperties">
|
|
||||||
<map>
|
|
||||||
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
|
|
||||||
<entry key="hibernate.hbm2ddl.auto" value="create-drop" />
|
|
||||||
<entry key="hibernate.show_sql" value="false" />
|
|
||||||
</map>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
<context:component-scan base-package="com.iluwatar.layers.dao">
|
|
||||||
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
|
|
||||||
</context:component-scan>
|
|
||||||
</beans>
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.iluwatar.layers.app;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = LayersApp.class)
|
||||||
|
class LayersAppTests {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
LayersAppTests(ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
assertNotNull(applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import entity.Cake;
|
||||||
|
import entity.CakeLayer;
|
||||||
|
import entity.CakeTopping;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package com.iluwatar.layers.exception;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import exception.CakeBakingException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,8 +35,10 @@ import org.junit.jupiter.api.Test;
|
|||||||
*
|
*
|
||||||
* @author Jeroen Meulemeester
|
* @author Jeroen Meulemeester
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class CakeBakingExceptionTest {
|
class CakeBakingExceptionTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testConstructor() {
|
void testConstructor() {
|
||||||
final var exception = new CakeBakingException();
|
final var exception = new CakeBakingException();
|
||||||
|
|||||||
@@ -30,33 +30,56 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.iluwatar.layers.dto.CakeInfo;
|
import com.iluwatar.layers.app.LayersApp;
|
||||||
import com.iluwatar.layers.dto.CakeLayerInfo;
|
import dto.CakeInfo;
|
||||||
import com.iluwatar.layers.dto.CakeToppingInfo;
|
import dto.CakeLayerInfo;
|
||||||
import com.iluwatar.layers.exception.CakeBakingException;
|
import dto.CakeToppingInfo;
|
||||||
|
import exception.CakeBakingException;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import service.CakeBakingServiceImpl;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/15/15 - 9:55 PM
|
* Date: 12/15/15 - 9:55 PM
|
||||||
*
|
*
|
||||||
* @author Jeroen Meulemeester
|
* @author Jeroen Meulemeester
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@SpringBootTest(classes = LayersApp.class)
|
||||||
class CakeBakingServiceImplTest {
|
class CakeBakingServiceImplTest {
|
||||||
|
|
||||||
@Test
|
private final CakeBakingServiceImpl cakeBakingService;
|
||||||
void testLayers() {
|
|
||||||
final var service = new CakeBakingServiceImpl();
|
|
||||||
|
|
||||||
final var initialLayers = service.getAvailableLayers();
|
@Autowired
|
||||||
|
CakeBakingServiceImplTest(CakeBakingServiceImpl cakeBakingService) {
|
||||||
|
this.cakeBakingService = cakeBakingService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
cakeBakingService.deleteAllCakes();
|
||||||
|
cakeBakingService.deleteAllLayers();
|
||||||
|
cakeBakingService.deleteAllToppings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
|
||||||
|
void testLayers() {
|
||||||
|
final var initialLayers = cakeBakingService.getAvailableLayers();
|
||||||
assertNotNull(initialLayers);
|
assertNotNull(initialLayers);
|
||||||
assertTrue(initialLayers.isEmpty());
|
assertTrue(initialLayers.isEmpty());
|
||||||
|
|
||||||
service.saveNewLayer(new CakeLayerInfo("Layer1", 1000));
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("Layer1", 1000));
|
||||||
service.saveNewLayer(new CakeLayerInfo("Layer2", 2000));
|
cakeBakingService.saveNewLayer(new CakeLayerInfo("Layer2", 2000));
|
||||||
|
|
||||||
final var availableLayers = service.getAvailableLayers();
|
final var availableLayers = cakeBakingService.getAvailableLayers();
|
||||||
assertNotNull(availableLayers);
|
assertNotNull(availableLayers);
|
||||||
assertEquals(2, availableLayers.size());
|
assertEquals(2, availableLayers.size());
|
||||||
for (final var layer : availableLayers) {
|
for (final var layer : availableLayers) {
|
||||||
@@ -70,16 +93,14 @@ class CakeBakingServiceImplTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testToppings() {
|
void testToppings() {
|
||||||
final var service = new CakeBakingServiceImpl();
|
final var initialToppings = cakeBakingService.getAvailableToppings();
|
||||||
|
|
||||||
final var initialToppings = service.getAvailableToppings();
|
|
||||||
assertNotNull(initialToppings);
|
assertNotNull(initialToppings);
|
||||||
assertTrue(initialToppings.isEmpty());
|
assertTrue(initialToppings.isEmpty());
|
||||||
|
|
||||||
service.saveNewTopping(new CakeToppingInfo("Topping1", 1000));
|
cakeBakingService.saveNewTopping(new CakeToppingInfo("Topping1", 1000));
|
||||||
service.saveNewTopping(new CakeToppingInfo("Topping2", 2000));
|
cakeBakingService.saveNewTopping(new CakeToppingInfo("Topping2", 2000));
|
||||||
|
|
||||||
final var availableToppings = service.getAvailableToppings();
|
final var availableToppings = cakeBakingService.getAvailableToppings();
|
||||||
assertNotNull(availableToppings);
|
assertNotNull(availableToppings);
|
||||||
assertEquals(2, availableToppings.size());
|
assertEquals(2, availableToppings.size());
|
||||||
for (final var topping : availableToppings) {
|
for (final var topping : availableToppings) {
|
||||||
@@ -93,28 +114,27 @@ class CakeBakingServiceImplTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBakeCakes() throws CakeBakingException {
|
void testBakeCakes() throws CakeBakingException {
|
||||||
final var service = new CakeBakingServiceImpl();
|
|
||||||
|
|
||||||
final var initialCakes = service.getAllCakes();
|
final var initialCakes = cakeBakingService.getAllCakes();
|
||||||
assertNotNull(initialCakes);
|
assertNotNull(initialCakes);
|
||||||
assertTrue(initialCakes.isEmpty());
|
assertTrue(initialCakes.isEmpty());
|
||||||
|
|
||||||
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
||||||
final var topping2 = new CakeToppingInfo("Topping2", 2000);
|
final var topping2 = new CakeToppingInfo("Topping2", 2000);
|
||||||
service.saveNewTopping(topping1);
|
cakeBakingService.saveNewTopping(topping1);
|
||||||
service.saveNewTopping(topping2);
|
cakeBakingService.saveNewTopping(topping2);
|
||||||
|
|
||||||
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
||||||
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
||||||
final var layer3 = new CakeLayerInfo("Layer3", 2000);
|
final var layer3 = new CakeLayerInfo("Layer3", 2000);
|
||||||
service.saveNewLayer(layer1);
|
cakeBakingService.saveNewLayer(layer1);
|
||||||
service.saveNewLayer(layer2);
|
cakeBakingService.saveNewLayer(layer2);
|
||||||
service.saveNewLayer(layer3);
|
cakeBakingService.saveNewLayer(layer3);
|
||||||
|
|
||||||
service.bakeNewCake(new CakeInfo(topping1, List.of(layer1, layer2)));
|
cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, layer2)));
|
||||||
service.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer3)));
|
cakeBakingService.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer3)));
|
||||||
|
|
||||||
final var allCakes = service.getAllCakes();
|
final var allCakes = cakeBakingService.getAllCakes();
|
||||||
assertNotNull(allCakes);
|
assertNotNull(allCakes);
|
||||||
assertEquals(2, allCakes.size());
|
assertEquals(2, allCakes.size());
|
||||||
for (final var cakeInfo : allCakes) {
|
for (final var cakeInfo : allCakes) {
|
||||||
@@ -130,61 +150,49 @@ class CakeBakingServiceImplTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBakeCakeMissingTopping() {
|
void testBakeCakeMissingTopping() {
|
||||||
final var service = new CakeBakingServiceImpl();
|
|
||||||
|
|
||||||
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
||||||
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
||||||
service.saveNewLayer(layer1);
|
cakeBakingService.saveNewLayer(layer1);
|
||||||
service.saveNewLayer(layer2);
|
cakeBakingService.saveNewLayer(layer2);
|
||||||
|
|
||||||
final var missingTopping = new CakeToppingInfo("Topping1", 1000);
|
final var missingTopping = new CakeToppingInfo("Topping1", 1000);
|
||||||
assertThrows(CakeBakingException.class, () -> {
|
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(missingTopping, List.of(layer1, layer2))));
|
||||||
service.bakeNewCake(new CakeInfo(missingTopping, List.of(layer1, layer2)));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBakeCakeMissingLayer() {
|
void testBakeCakeMissingLayer() {
|
||||||
final var service = new CakeBakingServiceImpl();
|
final var initialCakes = cakeBakingService.getAllCakes();
|
||||||
|
|
||||||
final var initialCakes = service.getAllCakes();
|
|
||||||
assertNotNull(initialCakes);
|
assertNotNull(initialCakes);
|
||||||
assertTrue(initialCakes.isEmpty());
|
assertTrue(initialCakes.isEmpty());
|
||||||
|
|
||||||
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
||||||
service.saveNewTopping(topping1);
|
cakeBakingService.saveNewTopping(topping1);
|
||||||
|
|
||||||
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
||||||
service.saveNewLayer(layer1);
|
cakeBakingService.saveNewLayer(layer1);
|
||||||
|
|
||||||
final var missingLayer = new CakeLayerInfo("Layer2", 2000);
|
final var missingLayer = new CakeLayerInfo("Layer2", 2000);
|
||||||
assertThrows(CakeBakingException.class, () -> {
|
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, missingLayer))));
|
||||||
service.bakeNewCake(new CakeInfo(topping1, List.of(layer1, missingLayer)));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBakeCakesUsedLayer() throws CakeBakingException {
|
void testBakeCakesUsedLayer() throws CakeBakingException {
|
||||||
final var service = new CakeBakingServiceImpl();
|
final var initialCakes = cakeBakingService.getAllCakes();
|
||||||
|
|
||||||
final var initialCakes = service.getAllCakes();
|
|
||||||
assertNotNull(initialCakes);
|
assertNotNull(initialCakes);
|
||||||
assertTrue(initialCakes.isEmpty());
|
assertTrue(initialCakes.isEmpty());
|
||||||
|
|
||||||
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
final var topping1 = new CakeToppingInfo("Topping1", 1000);
|
||||||
final var topping2 = new CakeToppingInfo("Topping2", 2000);
|
final var topping2 = new CakeToppingInfo("Topping2", 2000);
|
||||||
service.saveNewTopping(topping1);
|
cakeBakingService.saveNewTopping(topping1);
|
||||||
service.saveNewTopping(topping2);
|
cakeBakingService.saveNewTopping(topping2);
|
||||||
|
|
||||||
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
final var layer1 = new CakeLayerInfo("Layer1", 1000);
|
||||||
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
final var layer2 = new CakeLayerInfo("Layer2", 2000);
|
||||||
service.saveNewLayer(layer1);
|
cakeBakingService.saveNewLayer(layer1);
|
||||||
service.saveNewLayer(layer2);
|
cakeBakingService.saveNewLayer(layer2);
|
||||||
|
|
||||||
service.bakeNewCake(new CakeInfo(topping1, List.of(layer1, layer2)));
|
cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, layer2)));
|
||||||
assertThrows(CakeBakingException.class, () -> {
|
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer2))));
|
||||||
service.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer2)));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,16 +31,17 @@ import static org.mockito.Mockito.when;
|
|||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.AppenderBase;
|
import ch.qos.logback.core.AppenderBase;
|
||||||
import com.iluwatar.layers.dto.CakeInfo;
|
import dto.CakeInfo;
|
||||||
import com.iluwatar.layers.dto.CakeLayerInfo;
|
import dto.CakeLayerInfo;
|
||||||
import com.iluwatar.layers.dto.CakeToppingInfo;
|
import dto.CakeToppingInfo;
|
||||||
import com.iluwatar.layers.service.CakeBakingService;
|
import service.CakeBakingService;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import view.CakeViewImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/15/15 - 10:04 PM
|
* Date: 12/15/15 - 10:04 PM
|
||||||
@@ -68,9 +69,9 @@ class CakeViewImplTest {
|
|||||||
void testRender() {
|
void testRender() {
|
||||||
|
|
||||||
final var layers = List.of(
|
final var layers = List.of(
|
||||||
new CakeLayerInfo("layer1", 1000),
|
new CakeLayerInfo("layer1", 1000),
|
||||||
new CakeLayerInfo("layer2", 2000),
|
new CakeLayerInfo("layer2", 2000),
|
||||||
new CakeLayerInfo("layer3", 3000));
|
new CakeLayerInfo("layer3", 3000));
|
||||||
|
|
||||||
final var cake = new CakeInfo(new CakeToppingInfo("topping", 1000), layers);
|
final var cake = new CakeInfo(new CakeToppingInfo("topping", 1000), layers);
|
||||||
final var cakes = List.of(cake);
|
final var cakes = List.of(cake);
|
||||||
|
|||||||
@@ -333,7 +333,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<configLocation>google_checks.xml</configLocation>
|
<configLocation>google_checks.xml</configLocation>
|
||||||
<suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation>
|
<suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
<failOnViolation>true</failOnViolation>
|
<failOnViolation>true</failOnViolation>
|
||||||
<violationSeverity>warning</violationSeverity>
|
<violationSeverity>warning</violationSeverity>
|
||||||
<includeTestSourceDirectory>false</includeTestSourceDirectory>
|
<includeTestSourceDirectory>false</includeTestSourceDirectory>
|
||||||
|
|||||||
Reference in New Issue
Block a user