refactor: update layers parent, reformat code, update license headers

This commit is contained in:
Ilkka Seppälä
2024-03-30 08:34:54 +02:00
parent 6322d538cd
commit 7c1889b8e5
133 changed files with 3081 additions and 439 deletions
@@ -1,68 +1,98 @@
/*
* 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;
import dto.CakeInfo;
import dto.CakeLayerInfo;
import dto.CakeToppingInfo;
import exception.CakeBakingException;
import java.util.List;
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 service.CakeBakingService;
import view.CakeViewImpl;
import java.util.List;
/**
* The Runner class is the entry point of the application.
* It implements CommandLineRunner, which means it will execute the run method after the application context is loaded.
*
* <p>The Runner class is responsible for initializing the cake baking service with sample data and creating a view to render the cakes.
* It uses the CakeBakingService to save new layers and toppings and to bake new cakes.
* It also handles exceptions that might occur during the cake baking process.</p>
*/
@Component
@Slf4j
public class Runner implements CommandLineRunner {
private final CakeBakingService cakeBakingService;
public static final String STRAWBERRY = "strawberry";
private final CakeBakingService cakeBakingService;
public static final String STRAWBERRY = "strawberry";
@Autowired
public Runner(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
@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);
}
@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);
}
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,3 +1,27 @@
/*
* 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 org.springframework.boot.SpringApplication;
@@ -6,15 +30,23 @@ import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
/**
* The Layers pattern is a structural design pattern that organizes system architecture into
* distinct layers, each with a specific responsibility and abstraction level. This separation
* allows for increased modularity, facilitating independent development, maintenance, and reuse
* of each layer. Commonly, layers interact with each other through well-defined interfaces, with
* higher layers (more abstract) depending on lower layers (more concrete), but not vice versa,
* promoting a clear hierarchy and separation of concerns.
*/
@SpringBootApplication
@EnableJpaRepositories(basePackages = "dao")
@EntityScan(basePackages = "entity")
@ComponentScan(basePackages = {"com.iluwatar.layers", "service", "dto", "exception", "view" ,"dao"})
@ComponentScan(basePackages = {"com.iluwatar.layers", "service", "dto", "exception", "view", "dao"})
public class LayersApp {
public static void main(String[] args) {
SpringApplication.run(LayersApp.class, args);
public static void main(String[] args) {
SpringApplication.run(LayersApp.class, args);
}
}
}
+33 -32
View File
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package dto;
import java.util.List;
@@ -32,40 +33,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 -23
View File
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package dto;
import java.util.Optional;
@@ -31,30 +32,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);
}
}
+25 -24
View File
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package dto;
@@ -32,31 +33,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);
}
}
+40 -39
View File
@@ -22,17 +22,18 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package entity;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.CascadeType;
import jakarta.persistence.FetchType;
import java.util.HashSet;
import java.util.Set;
/**
* Cake entity.
@@ -40,50 +41,50 @@ import jakarta.persistence.FetchType;
@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());
}
}
+27 -17
View File
@@ -22,11 +22,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package entity;
import jakarta.persistence.*;
import lombok.*;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* CakeLayer entity.
@@ -40,24 +50,24 @@ import lombok.*;
@EqualsAndHashCode
public class CakeLayer {
@Id
@GeneratedValue
private Long id;
@Id
@GeneratedValue
private Long id;
private String name;
private String name;
private int calories;
private int calories;
@ManyToOne(cascade = CascadeType.ALL)
private Cake cake;
@ManyToOne(cascade = CascadeType.ALL)
private Cake cake;
public CakeLayer(String name, int calories) {
this.setName(name);
this.setCalories(calories);
}
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);
}
@Override
public String toString() {
return String.format("id=%s name=%s calories=%d", id, name, calories);
}
}
+27 -17
View File
@@ -22,11 +22,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package entity;
import jakarta.persistence.*;
import lombok.*;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* CakeTopping entity.
@@ -40,25 +50,25 @@ import lombok.*;
@EqualsAndHashCode
public class CakeTopping {
@Id
@GeneratedValue
private Long id;
@Id
@GeneratedValue
private Long id;
private String name;
private String name;
private int calories;
private int calories;
@OneToOne(cascade = CascadeType.ALL)
private Cake cake;
@OneToOne(cascade = CascadeType.ALL)
private Cake cake;
public CakeTopping(String name, int calories) {
this.setName(name);
this.setCalories(calories);
}
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);
}
@Override
public String toString() {
return String.format("id=%s name=%s calories=%d", id, name, calories);
}
}
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package exception;
import org.springframework.stereotype.Component;
@@ -32,12 +33,12 @@ import org.springframework.stereotype.Component;
@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);
}
}
@@ -22,15 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package service;
import dto.CakeInfo;
import dto.CakeLayerInfo;
import dto.CakeToppingInfo;
import exception.CakeBakingException;
import org.springframework.stereotype.Service;
import java.util.List;
import org.springframework.stereotype.Service;
/**
* Service for cake baking operations.
@@ -38,40 +38,40 @@ import java.util.List;
@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();
/**
* Get available cake layers.
*/
List<CakeLayerInfo> getAvailableLayers();
void deleteAllCakes();
void deleteAllCakes();
void deleteAllLayers();
void deleteAllLayers();
void deleteAllToppings();
void deleteAllToppings();
}
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package service;
import dao.CakeDao;
@@ -38,7 +39,6 @@ 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;
@@ -50,140 +50,149 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional
public class CakeBakingServiceImpl implements CakeBakingService {
private final CakeDao cakeDao;
private final CakeLayerDao cakeLayerDao;
private final CakeToppingDao cakeToppingDao;
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;
/**
* Constructs a new instance of CakeBakingServiceImpl.
*
* @param cakeDao the DAO for cake-related operations
* @param cakeLayerDao the DAO for cake layer-related operations
* @param cakeToppingDao the DAO for cake topping-related operations
*/
@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());
}
}
@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
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);
}
for (var layer : foundLayersToUpdate) {
layer.setCake(cake);
cakeLayerDao.save(layer);
}
} else {
throw new CakeBakingException(String.format("Topping %s is not available",
cakeInfo.cakeToppingInfo.name));
}
} 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 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));
}
@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;
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;
@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;
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 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 deleteAllCakes() {
cakeDao.deleteAll();
}
@Override
public void deleteAllLayers() {
cakeLayerDao.deleteAll();
}
@Override
public void deleteAllLayers() {
cakeLayerDao.deleteAll();
}
@Override
public void deleteAllToppings() {
cakeToppingDao.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;
@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;
}
}
+9 -8
View File
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package view;
import org.slf4j.Logger;
@@ -33,15 +34,15 @@ import service.CakeBakingService;
*/
public class CakeViewImpl implements View {
private final CakeBakingService cakeBakingService;
private final CakeBakingService cakeBakingService;
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
}
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
}
public void render() {
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
}
public void render() {
cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString()));
}
}
+2 -1
View File
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package view;
/**
@@ -29,6 +30,6 @@ package view;
*/
public interface View {
void render();
void render();
}
@@ -1,24 +1,49 @@
/*
* 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 static org.junit.jupiter.api.Assertions.assertNotNull;
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;
private final ApplicationContext applicationContext;
@Autowired
LayersAppTests(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Test
void contextLoads() {
assertNotNull(applicationContext);
}
@Autowired
LayersAppTests(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Test
void contextLoads() {
assertNotNull(applicationContext);
}
}
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.layers.entity;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -29,18 +30,17 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashSet;
import java.util.Set;
import entity.Cake;
import entity.CakeLayer;
import entity.CakeTopping;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
/**
* Date: 12/15/15 - 8:02 PM
*
* @author Jeroen Meulemeester
* This class contains unit tests for the Cake class.
* It tests the functionality of setting and getting the id, topping, and layers of a Cake object.
* It also tests the functionality of adding a layer to a Cake object and converting a Cake object to a string.
*/
class CakeTest {
@@ -70,9 +70,7 @@ class CakeTest {
assertNotNull(cake.getLayers());
assertTrue(cake.getLayers().isEmpty());
final var expectedLayers = Set.of(
new CakeLayer("layer1", 1000),
new CakeLayer("layer2", 2000),
final var expectedLayers = Set.of(new CakeLayer("layer1", 1000), new CakeLayer("layer2", 2000),
new CakeLayer("layer3", 3000));
cake.setLayers(expectedLayers);
assertEquals(expectedLayers, cake.getLayers());
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.layers.exception;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -31,27 +32,40 @@ import exception.CakeBakingException;
import org.junit.jupiter.api.Test;
/**
* Date: 12/15/15 - 7:57 PM
*
* @author Jeroen Meulemeester
* Tests for the {@link CakeBakingException} class.
* This class contains unit tests to verify the correct functionality
* of the {@code CakeBakingException} class constructors, including the default constructor
* and the constructor that accepts a message parameter.
*/
class CakeBakingExceptionTest {
/**
* Tests the default constructor of {@link CakeBakingException}.
* Ensures that an exception created with the default constructor has
* {@code null} as its message and cause.
*/
@Test
void testConstructor() {
final var exception = new CakeBakingException();
assertNull(exception.getMessage());
assertNull(exception.getCause());
assertNull(exception.getMessage(), "The message should be null for the default constructor.");
assertNull(exception.getCause(), "The cause should be null for the default constructor.");
}
/**
* Tests the constructor of {@link CakeBakingException} that accepts a message.
* Ensures that an exception created with this constructor correctly stores the provided message
* and has {@code null} as its cause.
*
* @param expectedMessage The message provided to the constructor.
*/
@Test
void testConstructorWithMessage() {
final var expectedMessage = "message";
final var exception = new CakeBakingException(expectedMessage);
assertEquals(expectedMessage, exception.getMessage());
assertNull(exception.getCause());
assertEquals(expectedMessage, exception.getMessage(),
"The stored message should match the expected message.");
assertNull(exception.getCause(),
"The cause should be null when an exception is created with only a message.");
}
}
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.layers.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -35,22 +36,19 @@ import dto.CakeInfo;
import dto.CakeLayerInfo;
import dto.CakeToppingInfo;
import exception.CakeBakingException;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import service.CakeBakingServiceImpl;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
/**
* Date: 12/15/15 - 9:55 PM
* Constructs a new instance of CakeBakingServiceImplTest.
*
* @author Jeroen Meulemeester
* @param cakeBakingService the service for cake baking operations
*/
@SpringBootTest(classes = LayersApp.class)
class CakeBakingServiceImplTest {
@@ -62,15 +60,14 @@ class CakeBakingServiceImplTest {
}
@BeforeEach
void setUp() {
cakeBakingService.deleteAllCakes();
cakeBakingService.deleteAllLayers();
cakeBakingService.deleteAllToppings();
}
void setUp() {
cakeBakingService.deleteAllCakes();
cakeBakingService.deleteAllLayers();
cakeBakingService.deleteAllToppings();
}
@Test
void testLayers() {
final var initialLayers = cakeBakingService.getAvailableLayers();
assertNotNull(initialLayers);
@@ -156,7 +153,8 @@ class CakeBakingServiceImplTest {
cakeBakingService.saveNewLayer(layer2);
final var missingTopping = new CakeToppingInfo("Topping1", 1000);
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(missingTopping, List.of(layer1, layer2))));
assertThrows(CakeBakingException.class,
() -> cakeBakingService.bakeNewCake(new CakeInfo(missingTopping, List.of(layer1, layer2))));
}
@Test
@@ -172,7 +170,8 @@ class CakeBakingServiceImplTest {
cakeBakingService.saveNewLayer(layer1);
final var missingLayer = new CakeLayerInfo("Layer2", 2000);
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, missingLayer))));
assertThrows(CakeBakingException.class,
() -> cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, missingLayer))));
}
@Test
@@ -192,7 +191,8 @@ class CakeBakingServiceImplTest {
cakeBakingService.saveNewLayer(layer2);
cakeBakingService.bakeNewCake(new CakeInfo(topping1, List.of(layer1, layer2)));
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer2))));
assertThrows(CakeBakingException.class, () -> cakeBakingService.bakeNewCake(
new CakeInfo(topping2, Collections.singletonList(layer2))));
}
}
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.layers.view;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -34,19 +35,19 @@ import ch.qos.logback.core.AppenderBase;
import dto.CakeInfo;
import dto.CakeLayerInfo;
import dto.CakeToppingInfo;
import service.CakeBakingService;
import java.util.LinkedList;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import service.CakeBakingService;
import view.CakeViewImpl;
/**
* Date: 12/15/15 - 10:04 PM
*
* @author Jeroen Meulemeester
* This class contains unit tests for the CakeViewImpl class.
* It tests the functionality of rendering cakes using the CakeViewImpl class.
* It also tests the logging functionality of the CakeViewImpl class.
*/
class CakeViewImplTest {
@@ -63,15 +64,13 @@ class CakeViewImplTest {
}
/**
* Verify if the cake view renders the expected result
* Verify if the cake view renders the expected result.
*/
@Test
void testRender() {
final var layers = List.of(
new CakeLayerInfo("layer1", 1000),
new CakeLayerInfo("layer2", 2000),
new CakeLayerInfo("layer3", 3000));
final var layers = List.of(new CakeLayerInfo("layer1", 1000), new CakeLayerInfo("layer2", 2000),
new CakeLayerInfo("layer3", 3000));
final var cake = new CakeInfo(new CakeToppingInfo("topping", 1000), layers);
final var cakes = List.of(cake);