Skip to content
Snippets Groups Projects
Commit 8495cebe authored by jez04's avatar jez04
Browse files

feat: :tada: solution

parent e7b8dd9f
Branches
No related merge requests found
......@@ -3,10 +3,10 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.vsb.fei.java2</groupId>
<artifactId>java2-lab04-v1</artifactId>
<artifactId>java2-lab05-v1</artifactId>
<version>0.0.1-SNAPHOST</version>
<name>java2-lab04-v1</name>
<name>java2-lab05-v1</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
......@@ -14,24 +14,8 @@
<maven.compiler.target>21</maven.compiler.target>
<lombok.version>1.18.34</lombok.version>
</properties>
<repositories>
<repository>
<id>vsb-education-release</id>
<url>https://artifactory.cs.vsb.cz/repository/education-releases/</url>
</repository>
<repository>
<id>vsb-education-snapshot</id>
<url>https://artifactory.cs.vsb.cz/repository/education-snapshot/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>cz.vsb.fei</groupId>
<artifactId>kelvin-java-unittest-support</artifactId>
<version>[0.1.4,)</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
......@@ -59,7 +43,6 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.3.232</version>
<scope>runtime</scope>
</dependency>
<dependency>
......@@ -96,7 +79,13 @@
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
<groupId>cz.vsb.fei</groupId>
<artifactId>kelvin-java-unittest-support</artifactId>
<version>[0.1.4,)</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
......@@ -114,6 +103,7 @@
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
......@@ -151,6 +141,7 @@
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!-- Ignore/Execute plugin execution in Eclipse (error of m2e
......@@ -183,4 +174,15 @@
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>vsb-education-release</id>
<url>https://artifactory.cs.vsb.cz/repository/education-releases/</url>
</repository>
<repository>
<id>vsb-education-snapshot</id>
<url>https://artifactory.cs.vsb.cz/repository/education-snapshot/</url>
</repository>
</repositories>
</project>
......@@ -5,12 +5,13 @@ WebWizard;262
ScreenSage;95
CodeCommander;276
FunctionFanatic;288
LogicLover;289
DataDetective;112
ScreenSage;181
BitBuilder;51
PixelArtist;242
RenderRogue;62
AppArchitect;225
DataDreamer;62
EmojiEnthusiast;101
siast;101
ByteBishop;53
PixelProdigy;196
PixelArtist;70
AppAlchemist;106
ScriptSensei;283
package lab.data;
public enum Level {
EASY, MEDIUM, HARD;
}
......@@ -3,6 +3,7 @@ package lab.data;
import java.util.Random;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
......@@ -13,16 +14,19 @@ import lombok.ToString;
@AllArgsConstructor
@EqualsAndHashCode
@ToString
@Builder(toBuilder = true)
public class Score {
private static final Random RANDOM = new Random();
private Long id;
private String name;
private int points;
private Level level;
public static Score generate() {
return new Score(getRandomNick(), RANDOM.nextInt(50, 300));
return new Score(null, getRandomNick(), RANDOM.nextInt(50, 300), Level.values()[RANDOM.nextInt(Level.values().length)]);
}
public static final String[] nicks = { "CyberSurfer", "PixelPioneer", "SocialSavvy", "DigitalDynamo", "ByteBuddy", "InstaGuru",
......
package lab.gui;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.sql.SQLException;
import org.h2.tools.Server;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
......@@ -10,6 +11,8 @@ import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import lab.Setting;
import lab.storage.JpaConnector;
import lombok.extern.log4j.Log4j2;
/**
* Class <b>App</b> - extends class Application and it is an entry point of the
......@@ -17,17 +20,31 @@ import lab.Setting;
*
* @author Java I
*/
@Log4j2
public class App extends Application {
private static Logger log = LogManager.getLogger(App.class);
private GameController gameController;
public static void main(String[] args) {
log.info("Application lauched");
Setting.configure(Setting.getInstanceForHardcoreGame().toBuilder().ufoMinPercentageHeight(0.4).build());
Setting.configure(Setting.builder().scoreStorageInterface(new JpaConnector()).build());
startH2WebServerToInspectDb();
launch(args);
}
private static void startH2WebServerToInspectDb() {
//Start HTTP server for access H2 DB for look inside
try {
Server server = Server.createWebServer();
log.info(server.getURL());
server.start();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void start(Stage primaryStage) {
try {
......@@ -57,6 +74,7 @@ public class App extends Application {
if (gameController != null) {
gameController.stop();
}
Setting.getInstance().getScoreStorageInterface().stop();
log.info("Exiting game");
System.exit(0);
}
......
package lab.gui;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Slider;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
......@@ -18,6 +21,7 @@ import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import lab.Setting;
import lab.data.Level;
import lab.data.Score;
import lab.game.BulletAnimated;
import lab.game.DrawingThread;
......@@ -57,6 +61,9 @@ public class GameController {
@FXML
private TableColumn<Score, Integer> pointsColumn;
@FXML
private TableColumn<Score, Level> levelColumn;
private DrawingThread timer;
@FXML
......@@ -80,7 +87,7 @@ public class GameController {
void btnGenerateScoreAction(ActionEvent event) {
Score score = Score.generate();
this.scores.getItems().add(score);
Setting.getInstance().getScoreStorageInterface().insertScore(score);
Setting.getInstance().getScoreStorageInterface().save(score);
}
@FXML
......@@ -93,6 +100,13 @@ public class GameController {
updateScoreTable(Setting.getInstance().getScoreStorageInterface().getFirstTen());
}
@FXML
void btnDeleteAction(ActionEvent event) {
List<Score> selectedScores = new ArrayList<>(scores.getSelectionModel().getSelectedItems());
Setting.getInstance().getScoreStorageInterface().delete(selectedScores);
updateScoreTable(Setting.getInstance().getScoreStorageInterface().getAll());
}
@FXML
void keyPressed(KeyEvent event) {
log.info(event.getCode());
......@@ -100,9 +114,9 @@ public class GameController {
}
@FXML
void canvasClicked(MouseEvent event) {
void canvasClicked(MouseEvent event) {
canvas.requestFocus();
}
}
@FXML
void keyReleased(KeyEvent event) {
......@@ -137,6 +151,13 @@ public class GameController {
nickColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points"));
levelColumn.setCellValueFactory(new PropertyValueFactory<>("level"));
btnDelete.setDisable(true);
scores.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
scores.getSelectionModel().getSelectedItems()
.addListener((ListChangeListener.Change<? extends Score> change) ->
btnDelete.setDisable(change.getList().isEmpty()));
initStorage();
log.info("Screeen initialized.");
......
......@@ -31,7 +31,7 @@ public class DbConnector implements ScoreStorageInterface {
Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery(query);) {
while (rs.next()) {
result.add(new Score(rs.getString("nick"), rs.getInt("points")));
result.add(new Score(null, rs.getString("nick"), rs.getInt("points"), null));
}
} catch (SQLException e) {
e.printStackTrace();
......@@ -50,7 +50,7 @@ public class DbConnector implements ScoreStorageInterface {
}
@Override
public void insertScore(Score score) {
public Score save(Score score) {
try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING);
PreparedStatement stm = con.prepareStatement("INSERT INTO scores VALUES (?, ?)");) {
stm.setString(1, score.getName());
......@@ -59,5 +59,26 @@ public class DbConnector implements ScoreStorageInterface {
} catch (SQLException e) {
e.printStackTrace();
}
return score;
}
@Override
public void delete(List<Score> scores) {
try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING);
PreparedStatement stm = con.prepareStatement("DELETE FROM scores WHERE nick=? AND points=?");) {
for (Score score : scores) {
stm.setString(1, score.getName());
stm.setInt(2, score.getPoints());
stm.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
/*nothing to do*/
}
}
......@@ -21,7 +21,7 @@ public class FileStorage implements ScoreStorageInterface {
if (Files.exists(Paths.get(SCORE_FILE_NAME))) {
try (Stream<String> lines = Files.lines(Paths.get(SCORE_FILE_NAME))) {
List<Score> result = lines.map(line -> line.split(";"))
.map(parts -> new Score(parts[0], Integer.parseInt(parts[1]))).toList();
.map(parts -> new Score(null, parts[0], Integer.parseInt(parts[1]), null)).toList();
return new ArrayList<>(result);
} catch (IOException e) {
e.printStackTrace();
......@@ -43,14 +43,33 @@ public class FileStorage implements ScoreStorageInterface {
}
@Override
public void insertScore(Score score) {
public Score save(Score score) {
List<Score> all = getAll();
all.add(score);
storeAll(all);
return score;
}
private void storeAll(List<Score> all) {
List<String> lines = all.stream().map(s -> String.format("%s;%d", s.getName(), s.getPoints())).toList();
try {
Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.CREATE);
Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.TRUNCATE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void delete(List<Score> scores) {
List<Score> all = getAll();
all.removeAll(scores);
storeAll(all);
}
@Override
public void stop() {
/*nothing to do*/
}
}
package lab.storage;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import lab.data.Score;
public class JpaConnector implements ScoreStorageInterface {
public JpaConnector() {
}
@Override
public List<Score> getAll() {
return Collections.emptyList();
}
@Override
public List<Score> getFirstTen() {
return Collections.emptyList();
}
@Override
public void init() {
}
@Override
public Score save(Score score) {
return null;
}
@Override
public void delete(List<Score> scores) {
}
@Override
public void stop() {
}
public Object getEntityManager() {
//return entity manager. Type Object is there because of compilation of empty task assignment
return null;
}
public Score find(long id) {
return null;
}
public void modifyNoPersistOrMerge(long id, Consumer<Score> motificator) {
}
}
package lab.storage;
import java.util.Collection;
import java.util.List;
import lab.data.Score;
......@@ -13,6 +12,10 @@ public interface ScoreStorageInterface {
void init();
void insertScore(Score score);
Score save(Score score);
void delete(List<Score> scores);
void stop();
}
\ No newline at end of file
module cz.vsb.fei.java2.lab03_module {
module cz.vsb.fei.java2.lab05_module {
requires transitive javafx.controls;
requires javafx.fxml;
requires javafx.base;
requires java.sql;
requires org.apache.logging.log4j;
requires static lombok;
requires com.h2database;
opens lab.gui to javafx.fxml;
opens lab.data to javafx.base;
......
......@@ -59,6 +59,7 @@
<columns>
<TableColumn fx:id="nickColumn" prefWidth="75.0" text="Nick" />
<TableColumn fx:id="pointsColumn" prefWidth="75.0" text="Points" />
<TableColumn fx:id="levelColumn" prefWidth="75.0" text="Úroveň" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
......@@ -67,7 +68,7 @@
<Button fx:id="btnGenerateScore" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnGenerateScoreAction" text="Generate new score" />
<Button fx:id="btnLoadAll" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadAllAction" text="Load all from DB" />
<Button fx:id="btnLoadFirstTen" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadFirstTenAction" text="Load First 10 from DB" />
<Button fx:id="btnDelete" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Delete score" />
<Button fx:id="btnDelete" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnDeleteAction" text="Delete score" />
</children>
</VBox>
</center>
......
......@@ -2,59 +2,176 @@ package jez04.structure.test;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.api.TestMethodOrder;
import cz.vsb.fei.kelvin.unittest.ProjectContains;
import cz.vsb.fei.kelvin.unittest.StructureHelper;
import cz.vsb.fei.kelvin.unittest.TextFileContains;
import cz.vsb.fei.kelvin.unittest.XmlFileContains;
import lab.data.Level;
import lab.data.Score;
import lab.storage.JpaConnector;
class ClassStructureTest {
StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
@Test
void lombokAsDependencyTest() throws URISyntaxException {
XmlFileContains xmlFileContains = new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'lombok']");
Path root = TextFileContains.getProjectRoot(getClass());
assertThat(root, xmlFileContains);
void jakartaAndHibernateAsDependencyTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'jakarta.persistence-api']"));
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'hibernate-core']"));
}
@Test
void lombokAsAnnotationProcessorTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/build/plugins/plugin/artifactId[text() = 'maven-compiler-plugin']"));
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/build/plugins/plugin/configuration/annotationProcessorPaths/path/artifactId[text() = 'lombok']"));
void jakartaInModulInfoTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "jakarta.persistence;"));
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "opens\\slab.data;"));
}
@Test
void moduleInfoTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains("module-info.java", "lombok;"));
void pesistenceXmlTest() throws URISyntaxException {
ProjectContains projectContains = new ProjectContains("persistence.xml");
assertThat(TextFileContains.getProjectRoot(getClass()), projectContains);
assertThat(projectContains.getFoundFiles(), Matchers.not(Matchers.hasSize(0)));
Path persistenceXml = projectContains.getFoundFiles().getFirst();
assertThat(persistenceXml.toAbsolutePath().toString(),
Matchers.endsWith(Paths.get("resources", "META-INF", "persistence.xml").toString()));
}
@CsvSource({
"@Getter,1",
"@Setter,1",
"@Log.*,1",
"@.*ArgsConstructor,1",
"@ToString,1",
"@Getter,3",
"@Setter,3",
"@Log.*,3",
"@.*ArgsConstructor,2",
"@ToString,3",
"@Log.*,5",
"@ToString,5" })
@ParameterizedTest(name = "use Lombok Annotation {0} {1} times")
void useLombokConfigTest(String text, int count) throws URISyntaxException, ClassNotFoundException {
@Test
void useEnumeratedTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains(".*\\.java", text).count(count).useRegExpForName(true));
new TextFileContains("Score.java", "@Enumerated\\(\\s*EnumType.STRING\\s*\\)"));
}
@TestMethodOrder(OrderAnnotation.class)
@Nested
class JpaConnectorTests {
private Score template = new Score(null, "Tester", 100, Level.EASY);
private JpaConnector connector;
@BeforeEach
void init() {
connector = new JpaConnector();
}
@AfterEach
void cleanUp() {
connector.stop();
}
boolean same(Score s1, Score s2) {
return s1.getLevel() == s2.getLevel() && s1.getPoints() == s2.getPoints()
&& Objects.equals(s1.getName(), s2.getName());
}
@Test
@Order(100)
void jpaScoreInsertTest() {
Score savedScore = connector.save(template);
assertThat(savedScore.getId(), Matchers.notNullValue());
}
@Test
@Order(200)
void jpaScoreReadTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
}
@Test
@Order(250)
void jpaReadSortedTest() {
for (int i = 0; i < 20; i++) {
connector.save(template.toBuilder().points(i).build());
}
List<Score> result = connector.getFirstTen();
assertThat(result, Matchers.hasSize(10));
for (int i = 0; i < result.size()-1; i++) {
assertThat(result.get(i).getPoints(), Matchers.greaterThanOrEqualTo(result.get(i+1).getPoints()));
}
}
@Test
@Order(300)
void jpaScoreModifyTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
for (Score score : savedScores) {
score.setLevel(Level.HARD);
connector.save(score);
}
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.not(Matchers.hasSize(0)));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaScoreDeleteTest() {
template.setLevel(Level.HARD);
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
connector.delete(savedScores);
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.hasSize(0));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaMergeTest() {
connector.save(template);
connector.find(template.getId());
Score copy = template.toBuilder().points(500).build();
Score result = connector.save(copy);
assertThat(result, Matchers.not(Matchers.sameInstance(copy)));
}
@Test
@Order(500)
void jpamodifyNoPersistNoMergeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException {
template.setName("aaa");
connector.save(template);
connector.modifyNoPersistOrMerge(template.getId(), score -> score.setName("ok"));
Object em = connector.getEntityManager();
em.getClass().getMethod("clear").invoke(em);
assertThat(connector.find(template.getId()).getName(), Matchers.equalTo("ok"));
TextFileContains textFileContains = new TextFileContains("JpaConnector.java",
"void\\s+modifyNoPersistOrMerge[\\s\\S]*}").multiline(true);
assertThat(TextFileContains.getProjectRoot(ClassStructureTest.class), textFileContains);
Path score = textFileContains.getFoundFiles().getFirst();
String src = Files.readString(score);
String method = Pattern.compile("void\\s+modifyNoPersistOrMerge[\\s\\S]*}").matcher(src).results().findFirst().get().group();
assertThat(method, Matchers.not(Matchers.containsString("persist")));
assertThat(method, Matchers.not(Matchers.containsString("merge")));
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment