mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-14 22:58:36 +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:
@@ -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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.dao;
|
||||
package dao;
|
||||
|
||||
import com.iluwatar.layers.entity.Cake;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import entity.Cake;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* CRUD repository for cakes.
|
||||
*/
|
||||
@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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.dao;
|
||||
package dao;
|
||||
|
||||
import com.iluwatar.layers.entity.CakeLayer;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import entity.CakeLayer;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* CRUD repository for cake layers.
|
||||
*/
|
||||
@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
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* CRUD repository cake toppings.
|
||||
*/
|
||||
@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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.dto;
|
||||
package dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -32,40 +32,40 @@ import java.util.Optional;
|
||||
*/
|
||||
public class CakeInfo {
|
||||
|
||||
public final Optional<Long> id;
|
||||
public final CakeToppingInfo cakeToppingInfo;
|
||||
public final List<CakeLayerInfo> cakeLayerInfos;
|
||||
public final Optional<Long> id;
|
||||
public final CakeToppingInfo cakeToppingInfo;
|
||||
public final List<CakeLayerInfo> cakeLayerInfos;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.of(id);
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.of(id);
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.empty();
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.empty();
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate calories.
|
||||
*/
|
||||
public int calculateTotalCalories() {
|
||||
var total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
|
||||
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
|
||||
return total;
|
||||
}
|
||||
/**
|
||||
* Calculate calories.
|
||||
*/
|
||||
public int calculateTotalCalories() {
|
||||
var total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
|
||||
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.orElse(-1L),
|
||||
cakeToppingInfo, cakeLayerInfos, calculateTotalCalories());
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.orElse(-1L),
|
||||
cakeToppingInfo, cakeLayerInfos, calculateTotalCalories());
|
||||
}
|
||||
}
|
||||
+24
-24
@@ -22,7 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.dto;
|
||||
package dto;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -31,30 +31,30 @@ import java.util.Optional;
|
||||
*/
|
||||
public class CakeLayerInfo {
|
||||
|
||||
public final Optional<Long> id;
|
||||
public final String name;
|
||||
public final int calories;
|
||||
public final Optional<Long> id;
|
||||
public final String name;
|
||||
public final int calories;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeLayerInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeLayerInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeLayerInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeLayerInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CakeLayerInfo id=%d name=%s calories=%d", id.orElse(-1L), name, calories);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.dto;
|
||||
package dto;
|
||||
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -31,31 +32,31 @@ import java.util.Optional;
|
||||
*/
|
||||
public class CakeToppingInfo {
|
||||
|
||||
public final Optional<Long> id;
|
||||
public final String name;
|
||||
public final int calories;
|
||||
public final Optional<Long> id;
|
||||
public final String name;
|
||||
public final int calories;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeToppingInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeToppingInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeToppingInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CakeToppingInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CakeToppingInfo id=%d name=%s calories=%d",
|
||||
id.orElse(-1L), name, calories);
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CakeToppingInfo id=%d name=%s calories=%d",
|
||||
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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.entity;
|
||||
package entity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.FetchType;
|
||||
|
||||
/**
|
||||
* Cake entity.
|
||||
@@ -40,50 +40,50 @@ import javax.persistence.OneToOne;
|
||||
@Entity
|
||||
public class Cake {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@OneToOne(cascade = CascadeType.REMOVE)
|
||||
private CakeTopping topping;
|
||||
@OneToOne(cascade = CascadeType.REMOVE)
|
||||
private CakeTopping topping;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
||||
private Set<CakeLayer> layers;
|
||||
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
||||
private Set<CakeLayer> layers;
|
||||
|
||||
public Cake() {
|
||||
setLayers(new HashSet<>());
|
||||
}
|
||||
public Cake() {
|
||||
setLayers(new HashSet<>());
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CakeTopping getTopping() {
|
||||
return topping;
|
||||
}
|
||||
public CakeTopping getTopping() {
|
||||
return topping;
|
||||
}
|
||||
|
||||
public void setTopping(CakeTopping topping) {
|
||||
this.topping = topping;
|
||||
}
|
||||
public void setTopping(CakeTopping topping) {
|
||||
this.topping = topping;
|
||||
}
|
||||
|
||||
public Set<CakeLayer> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
public Set<CakeLayer> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
public void setLayers(Set<CakeLayer> layers) {
|
||||
this.layers = layers;
|
||||
}
|
||||
public void setLayers(Set<CakeLayer> layers) {
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
public void addLayer(CakeLayer layer) {
|
||||
this.layers.add(layer);
|
||||
}
|
||||
public void addLayer(CakeLayer layer) {
|
||||
this.layers.add(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("id=%s topping=%s layers=%s", id, topping, layers.toString());
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("id=%s topping=%s layers=%s", id, topping, layers.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.*;
|
||||
|
||||
/**
|
||||
* CakeLayer entity.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@EqualsAndHashCode
|
||||
public class CakeLayer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.exception;
|
||||
package exception;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Custom exception used in cake baking.
|
||||
*/
|
||||
@Component
|
||||
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) {
|
||||
super(message);
|
||||
}
|
||||
public CakeBakingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+39
-29
@@ -22,46 +22,56 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Service for cake baking operations.
|
||||
*/
|
||||
@Service
|
||||
public interface CakeBakingService {
|
||||
|
||||
/**
|
||||
* Bakes new cake according to parameters.
|
||||
*/
|
||||
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
||||
/**
|
||||
* Bakes new cake according to parameters.
|
||||
*/
|
||||
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
||||
|
||||
/**
|
||||
* Get all cakes.
|
||||
*/
|
||||
List<CakeInfo> getAllCakes();
|
||||
/**
|
||||
* Get all cakes.
|
||||
*/
|
||||
List<CakeInfo> getAllCakes();
|
||||
|
||||
/**
|
||||
* Store new cake topping.
|
||||
*/
|
||||
void saveNewTopping(CakeToppingInfo toppingInfo);
|
||||
/**
|
||||
* Store new cake topping.
|
||||
*/
|
||||
void saveNewTopping(CakeToppingInfo toppingInfo);
|
||||
|
||||
/**
|
||||
* Get available cake toppings.
|
||||
*/
|
||||
List<CakeToppingInfo> getAvailableToppings();
|
||||
/**
|
||||
* Get available cake toppings.
|
||||
*/
|
||||
List<CakeToppingInfo> getAvailableToppings();
|
||||
|
||||
/**
|
||||
* Add new cake layer.
|
||||
*/
|
||||
void saveNewLayer(CakeLayerInfo layerInfo);
|
||||
/**
|
||||
* Add new cake layer.
|
||||
*/
|
||||
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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.view;
|
||||
package view;
|
||||
|
||||
import com.iluwatar.layers.service.CakeBakingService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import service.CakeBakingService;
|
||||
|
||||
/**
|
||||
* View implementation for displaying cakes.
|
||||
*/
|
||||
@Slf4j
|
||||
public class CakeViewImpl implements View {
|
||||
|
||||
private final CakeBakingService cakeBakingService;
|
||||
private final CakeBakingService cakeBakingService;
|
||||
|
||||
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
||||
this.cakeBakingService = cakeBakingService;
|
||||
}
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
|
||||
|
||||
public void render() {
|
||||
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
|
||||
}
|
||||
public CakeViewImpl(CakeBakingService cakeBakingService) {
|
||||
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
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.layers.view;
|
||||
package view;
|
||||
|
||||
/**
|
||||
* View interface.
|
||||
*/
|
||||
public interface View {
|
||||
|
||||
void render();
|
||||
void render();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user