Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2a69407
added and edited doGet method in LogicServlet class
Jun 16, 2024
0d48d79
added InitServlet class and doGet method in this class
Jun 16, 2024
fcb8ec1
created a game display, added basic styles
Jun 16, 2024
fcf8608
checkWin method created
Jun 16, 2024
8376a9c
added check for winner in doGet in LogicServlet
Jun 16, 2024
9fc1992
winner label added
Jun 16, 2024
5a068e1
restart button added
Jun 16, 2024
e565dcd
RestartServlet added
Jun 16, 2024
7a2ff43
RestartServlet added
Jun 16, 2024
1c6c057
RestartServlet added
Jun 16, 2024
f948e63
added logic for draw
Jun 16, 2024
5f9c2ae
deleted unused library
Jun 16, 2024
80b2d05
all tests for Field class are done
Jun 27, 2024
5fbce04
added restart servlet test class
Jun 27, 2024
82ed753
added LogicServletTest and testOccupiedCell test
Jun 27, 2024
2edd448
added testEmptyCellSetCross, testCheckWinCross, testCheckWinNought, t…
Jun 30, 2024
47939b6
InitServletTest and testDoGet test added
Jun 30, 2024
8b3fa11
added logs to RestartServlet
Jun 30, 2024
2ad78a8
added logs to RestartServlet
Jun 30, 2024
e9a41b7
added logs to InitServlet
Jun 30, 2024
3f31599
added logs to LogicServlet
Jun 30, 2024
4fb4c10
edited logs
Jun 30, 2024
8354575
added logs to Field
Jun 30, 2024
f2ead9c
deleted unnecessary tests
Jul 1, 2024
8bbbd39
wrote logs to file
Jul 1, 2024
aac2213
Update InitServlet.java
dosstacy Jul 1, 2024
74a2fcf
Update LogicServlet.java
dosstacy Jul 1, 2024
7c3c071
Update RestartServlet.java
dosstacy Jul 1, 2024
d040df7
Update Field.java
dosstacy Jul 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
</properties>

<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
Expand All @@ -28,6 +38,29 @@
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.12</version>
</dependency>
</dependencies>

<build>
Expand All @@ -37,6 +70,24 @@
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>

<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
8 changes: 6 additions & 2 deletions src/main/java/com/tictactoe/Field.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Field {
private final Map<Integer, Sign> field;
private static final Logger LOGGER = LogManager.getLogger(Field.class);

public Field() {
field = new HashMap<>();
Expand Down Expand Up @@ -40,6 +43,7 @@ public List<Sign> getFieldData() {
}

public Sign checkWin() {
LOGGER.info("Checking for winner");
List<List<Integer>> winPossibilities = List.of(
List.of(0, 1, 2),
List.of(3, 4, 5),
Expand All @@ -53,10 +57,10 @@ public Sign checkWin() {

for (List<Integer> winPossibility : winPossibilities) {
if (field.get(winPossibility.get(0)) == field.get(winPossibility.get(1))
&& field.get(winPossibility.get(0)) == field.get(winPossibility.get(2))) {
&& field.get(winPossibility.get(0)) == field.get(winPossibility.get(2))) {
return field.get(winPossibility.get(0));
}
}
return Sign.EMPTY;
}
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/tictactoe/InitServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.tictactoe;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "InitServlet", value = "/start")
public class InitServlet extends HttpServlet {
private static final Logger LOGGER = LogManager.getLogger(InitServlet.class);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
LOGGER.info("Handling GET request for /start");
HttpSession currentSession = req.getSession(true);

Field field = new Field();
List<Sign> data = field.getFieldData();

currentSession.setAttribute("field", field);
currentSession.setAttribute("data", data);

LOGGER.info("Forwarding request to /index.jsp");
try {
getServletContext().getRequestDispatcher("/index.jsp").forward(req, resp);
}catch (ServletException | IOException e) {
LOGGER.error("An exception occurred while forwarding request to /index.jsp", e);
}
}
}
123 changes: 123 additions & 0 deletions src/main/java/com/tictactoe/LogicServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.tictactoe;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "LogicServlet", value = "/logic")
public class LogicServlet extends HttpServlet {
private static final Logger LOGGER = LogManager.getLogger(LogicServlet.class);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
LOGGER.info("LogicServlet doGet");
HttpSession currentSession = req.getSession();
Field currentField = extractField(currentSession);

int index = getSelectedIndex(req);
Sign currentSign = currentField.getField().get(index);

if (Sign.EMPTY != currentSign) {
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
try {
dispatcher.forward(req, resp);
}catch (ServletException | IOException e) {
LOGGER.error("An exception occurred while forwarding to /index.jsp", e);
}
return;
}
currentField.getField().put(index, Sign.CROSS);
LOGGER.debug("Field updated successfully: {}", currentField.getField());
try {
if (checkWin(resp, currentSession, currentField)) {
return;
}
}catch (IOException e) {
LOGGER.error("An exception occurred while checking winner (cross)", e);
}

int emptyFieldIndex = currentField.getEmptyFieldIndex();
if (emptyFieldIndex >= 0) {
currentField.getField().put(emptyFieldIndex, Sign.NOUGHT);
LOGGER.debug("Field updated successfully: {}", currentField.getField());
try {
if (checkWin(resp, currentSession, currentField)) {
return;
}
}catch (IOException e) {
LOGGER.error("An exception occurred while checking winner (nought)", e);
}
}else{
currentSession.setAttribute("draw", true);

List<Sign> data = currentField.getFieldData();
currentSession.setAttribute("data", data);
try {
resp.sendRedirect("/index.jsp");
}catch (IOException e) {
LOGGER.error("An exception occurred while redirecting to /index.jsp", e);
}
return;
}

List<Sign> data = currentField.getFieldData();

currentSession.setAttribute("data", data);
currentSession.setAttribute("field", currentField);

try {
resp.sendRedirect("/index.jsp");
}catch (IOException e) {
LOGGER.error("An exception occurred while redirecting to /index.jsp", e);
}
}

private int getSelectedIndex(HttpServletRequest request) {
LOGGER.info("Getting 'click' parameter from request");
String click = request.getParameter("click");
if (click != null && click.matches("\\d+")) {
return Integer.parseInt(click);
} else {
LOGGER.warn("'click' parameter is not a valid number: {}", click);
return 0;
}
}

private Field extractField(HttpSession session) {
Object field = session.getAttribute("field");
LOGGER.info("Extracting 'field' attribute from session");
if(Field.class != field.getClass()) {
LOGGER.error("Session contains an invalid 'field' attribute: {}", field.getClass());
session.invalidate();
throw new RuntimeException("Session is broken, try one more time");
}
return (Field) field;
}

private boolean checkWin(HttpServletResponse response, HttpSession currentSession, Field field) throws IOException {
Sign winner = field.checkWin();
if (Sign.CROSS == winner || Sign.NOUGHT == winner) {
currentSession.setAttribute("winner", winner);

List<Sign> data = field.getFieldData();

currentSession.setAttribute("data", data);

try {
response.sendRedirect("/index.jsp");
}catch (IOException e){
LOGGER.error("IOException occurred while redirecting to /index.jsp", e);
}
return true;
}
return false;
}
}
26 changes: 26 additions & 0 deletions src/main/java/com/tictactoe/RestartServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tictactoe;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "RestartServlet", value = "/restart")
public class RestartServlet extends HttpServlet {
private static final Logger LOGGER = LogManager.getLogger(RestartServlet.class);

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
LOGGER.info("Invalidating session and redirecting to /start");
try {
req.getSession().invalidate();
resp.sendRedirect("/start");
}catch (IOException e){
LOGGER.error("IOException occurred while redirecting to /start", e);
}
}
}
24 changes: 24 additions & 0 deletions src/main/resources/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Configuration status="WARN">
<Properties>
<Property name="LOG_PATTERN">%date %level %logger{10} [%file:%line] %msg%n</Property>
<Property name="APP_LOG_ROOT">C:/Moje/project-servlet</Property>
</Properties>

<Appenders>
<RollingFile name="FILE" fileName="${APP_LOG_ROOT}/tic-tac-toe.log"
filePattern="${APP_LOG_ROOT}/tic-tac-toe-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>

<Loggers>
<Root level="ALL">
<AppenderRef ref="FILE"/>
</Root>
</Loggers>

</Configuration>
53 changes: 51 additions & 2 deletions src/main/webapp/index.jsp
Original file line number Diff line number Diff line change
@@ -1,16 +1,65 @@
<%@ page import="com.tictactoe.Sign" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html>
<html>
<head>
<title>Tic-Tac-Toe</title>
<link href="static/main.css" rel="stylesheet">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
</head>
<body>
<h1>Tic-Tac-Toe</h1>

<table>
<tr>
<td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td>
<td onclick="window.location='/logic?click=1'">${data.get(1).getSign()}</td>
<td onclick="window.location='/logic?click=2'">${data.get(2).getSign()}</td>
</tr>
<tr>
<td onclick="window.location='/logic?click=3'">${data.get(3).getSign()}</td>
<td onclick="window.location='/logic?click=4'">${data.get(4).getSign()}</td>
<td onclick="window.location='/logic?click=5'">${data.get(5).getSign()}</td>
</tr>
<tr>
<td onclick="window.location='/logic?click=6'">${data.get(6).getSign()}</td>
<td onclick="window.location='/logic?click=7'">${data.get(7).getSign()}</td>
<td onclick="window.location='/logic?click=8'">${data.get(8).getSign()}</td>
</tr>
</table>

<script>
<hr>

<c:set var="CROSSES" value="<%=Sign.CROSS%>"/>
<c:set var="NOUGHTS" value="<%=Sign.NOUGHT%>"/>

<c:if test="${winner == CROSSES}">
<h1>CROSSES WIN!</h1>
<button onclick="restart()">Start again</button>
</c:if>
<c:if test="${winner == NOUGHTS}">
<h1>NOUGHTS WIN!</h1>
<button onclick="restart()">Start again</button>
</c:if>
<c:if test="${draw}">
<h1>IT'S A DRAW</h1>
<br>
<button onclick="restart()">Start again</button>
</c:if>

<script>
function restart() {
$.ajax({
url: '/restart',
type: 'POST',
contentType: 'application/json;charset=UTF-8',
async: false,
success: function () {
location.reload();
}
});
}
</script>

</body>
Expand Down
Binary file added src/main/webapp/static/img/cross.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/webapp/static/img/nought.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading