commit 6afdc469cddead3fa044abae04af20a27d45471f
parent 4a84ce114eec4b6818ec7f1f378c08a188cf61c5
Author: William Lindholm <william_lindholm@outlook.com>
Date: Thu, 7 Nov 2024 13:03:29 +0000
Imported TicTacToe web service
Diffstat:
9 files changed, 805 insertions(+), 0 deletions(-)
diff --git a/TicTacToeWS/nb-configuration.xml b/TicTacToeWS/nb-configuration.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-shared-configuration>
+ <!--
+This file contains additional configuration written by modules in the NetBeans IDE.
+The configuration is intended to be shared among all the users of project and
+therefore it is assumed to be part of version control checkout.
+Without this configuration present, some functionality in the IDE may be limited or fail altogether.
+-->
+ <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
+ <!--
+Properties that influence various parts of the IDE, especially code formatting and the like.
+You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
+That way multiple projects can share the same settings (useful for formatting rules for example).
+Any value defined here will override the pom.xml file value but is only applicable to the current project.
+-->
+ <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>10-web</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>
+ <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>gfv700ee10</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
+ <org-netbeans-modules-maven-j2ee.netbeans_2e_copy_2e_static_2e_resources_2e_on_2e_save>false</org-netbeans-modules-maven-j2ee.netbeans_2e_copy_2e_static_2e_resources_2e_on_2e_save>
+ </properties>
+</project-shared-configuration>
diff --git a/TicTacToeWS/pom.xml b/TicTacToeWS/pom.xml
@@ -0,0 +1,68 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com</groupId>
+ <artifactId>TicTacToeWS</artifactId>
+ <version>1</version>
+ <packaging>war</packaging>
+ <name>TicTacToeWS-1</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <jakartaee>10.0.0</jakartaee>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>jakarta.platform</groupId>
+ <artifactId>jakarta.jakartaee-api</artifactId>
+ <version>${jakartaee}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>8.0.33</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <source>11</source>
+ <target>11</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>3.3.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>3.3.2</version>
+ <configuration>
+ <failOnError>true</failOnError>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>3.6.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
+\ No newline at end of file
diff --git a/TicTacToeWS/src/main/java/com/tttws/TTT_MySQL.java b/TicTacToeWS/src/main/java/com/tttws/TTT_MySQL.java
@@ -0,0 +1,184 @@
+/*
+ Implements access to the MySQL database "tictactoe"
+ */
+package com.tttws;
+
+import static java.lang.System.exit;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ *
+ * @author petar
+ */
+public class TTT_MySQL {
+
+ private Connection connect = null;
+ private Statement statement = null;
+ private PreparedStatement preparedStatement = null;
+ private ResultSet resultSet = null;
+
+ /**
+ * Parameterized constructor to connect to any MySQL DB on any MySQL DBMS.
+ *
+ * @param host where is the DBMS?
+ * @param username who are you?
+ * @param password what is your password?
+ * @param database which database do you wish to use?
+ */
+ public TTT_MySQL(String host, String username, String password, String database) {
+ String url = "";
+ url = "jdbc:mysql://" + host + "/" + database;
+ try {
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ connect = DriverManager.getConnection(url, username, password);
+ } catch (SQLException | ClassNotFoundException e) {
+ exit(-1);
+ }
+ }
+
+ /**
+ * Used to retrieve information from a table.
+ *
+ * @param SQLCmd The SELECT query you wish to run.
+ * @return The result of the query encoded as a comma separated list of
+ * fields with a new line for each row.
+ */
+ public String retrieve(String SQLCmd) {
+ String result = "";
+ try {
+ statement = connect.createStatement();
+ resultSet = statement.executeQuery(SQLCmd);
+ result = writeResultSet(resultSet);
+ } catch (Exception e) {
+ return "ERROR";
+ }
+ return result;
+ }
+
+ /**
+ * Used to update information in a table.
+ *
+ * @param SQLCmd The UPDATE command you wish to run.
+ * @return either how many rows were updated or the text string "ERROR".
+ */
+ public String update(String SQLCmd) {
+ try {
+ preparedStatement = connect.prepareStatement(SQLCmd);
+ int rows = preparedStatement.executeUpdate();
+ return "UPDATED " + rows + " ROWS.";
+ } catch (Exception e) {
+ return "ERROR";
+ }
+ }
+
+ /**
+ * Used to insert information into a table.
+ *
+ * @param SQLCmd The INSERT query you wish to run.
+ * @return either how many rows were inserted or the text string "ERROR".
+ */
+ public String insert(String SQLCmd) {
+ try {
+ preparedStatement = connect.prepareStatement(SQLCmd);
+ int rows = preparedStatement.executeUpdate();
+ return "INSERTED " + rows + " ROWS.";
+ } catch (Exception e) {
+ return "ERROR";
+ }
+ }
+
+ /**
+ * Used to remove data from a table.
+ *
+ * @param SQLCmd The DELETE query you wish to run.
+ * @return either how many rows were removed or the text string "ERROR".
+ */
+ public String remove(String SQLCmd) {
+ try {
+ preparedStatement = connect.prepareStatement(SQLCmd);
+ int rows = preparedStatement.executeUpdate();
+ return "REMOVED " + rows + " ROWS.";
+ } catch (Exception e) {
+ return "ERROR";
+ }
+ }
+
+ /**
+ * Used to get the fields names of a resultset.
+ *
+ * @param resultSet the resultset you wish to get the field names of.
+ * @return the metadata of the resultset.
+ * @throws SQLException
+ */
+ private String writeMetaData(ResultSet resultSet) throws SQLException {
+ String result = "";
+ result += "The columns in the table are: ";
+ result += "Table: " + resultSet.getMetaData().getTableName(1);
+ for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
+ result += "Column " + i + " " + resultSet.getMetaData().getColumnName(i);
+ }
+ return result;
+ }
+
+ /**
+ * Used to turn a resultset into a digestible form.
+ *
+ * @param resultSet the resultset you wish to consume.
+ * @return the resultset encoded as fields separated by commas and rows
+ * separated by the new line character (\n).
+ * @throws SQLException
+ */
+ private String writeResultSet(ResultSet resultSet) throws SQLException {
+ String result = "";
+ /*switch(query) {
+ case "login":
+ while(resultSet.next()) {
+ int userID = resultSet.getInt("autokey");
+ result += userID + "\n";
+ }
+ break;
+
+ } */
+ int cols = resultSet.getMetaData().getColumnCount();
+ int rows = 0;
+ while (resultSet.next()) {
+ if (rows > 0) {
+ result += "\n";
+ }
+ for (int i = 1; i <= cols; i++) {
+ result += resultSet.getObject(i).toString();
+ result += ",";
+ }
+ int len = result.length();
+ result = result.substring(0, (len - 1));
+ rows++;
+ }
+ return result;
+ }
+
+ /**
+ * Used to close all objects used to talk with the DB and DBMS.
+ */
+ public void close() {
+ try {
+ if (resultSet != null) {
+ resultSet.close();
+ }
+
+ if (statement != null) {
+ statement.close();
+ }
+
+ if (connect != null) {
+ connect.close();
+ }
+ } catch (SQLException e) {
+ System.out.println("Exception: " + e.getMessage());
+ }
+ }
+}
diff --git a/TicTacToeWS/src/main/java/com/tttws/TicTacToeWS.java b/TicTacToeWS/src/main/java/com/tttws/TicTacToeWS.java
@@ -0,0 +1,475 @@
+/*
+ * Implements the Tic Tac Toe Web Service.
+ */
+package com.tttws;
+
+import jakarta.jws.WebMethod;
+import jakarta.jws.WebParam;
+import jakarta.jws.WebService;
+import jakarta.jws.soap.SOAPBinding;
+
+/*
+ * Tic Tac Toe Web Service
+ */
+
+/**
+ *
+ * @author petar
+ */
+
+@WebService(serviceName = "TicTacToeWebService")
+@SOAPBinding(style = SOAPBinding.Style.RPC)
+public class TicTacToeWS {
+
+ private final TTT_MySQL dao;
+
+ /**
+ * Web Service constructor
+ */
+ public TicTacToeWS() {
+ dao = new TTT_MySQL("localhost", "root", "", "tictactoe");
+ }
+
+ /**
+ * Used to login to the system
+ * @param username the username of the user logging in.
+ * @param password the password of the user logging in.
+ * @return either 0 if incorrect details, an integer greater than 0 (which is the users id) if correct details, -1 if there is a general error.
+ */
+ @WebMethod(operationName = "login")
+ public int login(@WebParam(name = "username") String username, @WebParam(name = "password") String password) {
+ try {
+ String sqlCmd = "SELECT autokey FROM users WHERE username = '" + username;
+ sqlCmd += "' AND password = SHA1('" + password + "') AND isactive = 1;";
+ String result = dao.retrieve(sqlCmd);
+ if("ERROR".equals(result)) {
+ return 0;
+ } else {
+ return Integer.parseInt(result);
+ }
+ } catch(Exception e) {
+ System.out.println("Error is : " + e.getMessage());
+ return -1;
+ }
+ }
+
+ /**
+ * Used to register a new user on the system.
+ * @param username the username of the new user.
+ * @param password the password of the new user.
+ * @param name - the name of the new user.
+ * @param surname the surname of the new user.
+ * @return The user provides their username, password, name and surname. If successful, the method returns the users id on the system (the autokey
+ * field from the users table). If unsuccessful, it returns either “ERROR-REPEAT” if a user with that username already exists, “ERROR-INSERT” if the
+ * method could not add the data to the users table, “ERROR-RETRIEVE “ if the method cannot retrieve the newly inserted data from the users table, or
+ * “ERROR-DB” if the method cannot find the DB.
+ */
+ @WebMethod(operationName = "register")
+ public String register(@WebParam(name = "username") String username, @WebParam(name = "password") String password, @WebParam(name = "name") String name, @WebParam(name = "surname") String surname) {
+ String sqlCmd = "";
+
+ sqlCmd = "SELECT COUNT(*) FROM users WHERE username = '" + username + "';";
+ try {
+ String result = "";
+ result = dao.retrieve(sqlCmd);
+ if(result.equals("0")) {
+ sqlCmd = "INSERT INTO users VALUES (default, '";
+ sqlCmd += name + "', '" + surname + "', '" + username + "', SHA1('";
+ sqlCmd += password + "'), 1, default);";
+ System.out.println(sqlCmd);
+ try {
+ result = dao.insert(sqlCmd);
+ if(!"INSERTED 1 ROWS.".equals(result)) {
+ return "ERROR-INSERT";
+ } else {
+ sqlCmd = "SELECT autokey FROM users WHERE username = '" + username;
+ sqlCmd += "' AND password = SHA1('" + password + "') AND isactive = 1;";
+
+ try {
+ result = dao.retrieve(sqlCmd);
+ return result;
+ } catch(Exception g) {
+ return "ERROR-RETRIEVE";
+ }
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ } else {
+ return "ERROR-REPEAT";
+ }
+ } catch(Exception u) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Used to create a new game.
+ * @param uid the user id of the user creating the new game.
+ * @return either the id of the new game (returned as a string), or "ERROR-NOTFOUND", "ERROR-RETRIEVE", or "ERROR-INSERT" if the game couldn't be created, or "ERROR-DB" if unable to talk to the DB or DBMS.
+ */
+ @WebMethod(operationName = "newGame")
+ public String newGame(@WebParam(name = "uid") int uid) {
+ String sqlCmd = "INSERT INTO games VALUES(default, " + uid + ", NULL, -1, default);";
+ try {
+ String result = dao.insert(sqlCmd);
+ if(result.equals("INSERTED 1 ROWS.")) {
+ sqlCmd = "SELECT autokey FROM games WHERE gamestate = -1 AND p1 = " + uid + " AND p2 IS NULL ORDER BY autokey DESC LIMIT 1;";
+ try {
+ result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOTFOUND";
+ }
+ } catch(Exception g) {
+ return "ERROR-RETRIEVE";
+ }
+ } else {
+ return "ERROR-INSERT";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Used to join an existing game.
+ * @param uid the user id of the person joining the game.
+ * @param gid the game id of the game the player wants to join.
+ * @return 1 (as a string) if able to join, 0 (as a string) if unable to join, or "ERROR-DB" if unable to talk to the DB or DBMS.
+ */
+ @WebMethod(operationName = "joinGame")
+ public String joinGame(@WebParam(name = "uid") int uid, @WebParam(name = "gid") int gid) {
+ String sqlCmd = "UPDATE games SET p2 = " + uid + ", gamestate = 0 WHERE autokey = " + gid + ";";
+ try {
+ String result = dao.update(sqlCmd);
+ if(result.equals("UPDATED 1 ROWS.")) {
+ return "1";
+ } else {
+ return "0";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Returns the current board as a formatted string.
+ * @param gid the game id of the game whose board we want to see.
+ * @return Used to return all moves taken to date for a particular game. If successful, the method returns the moves taken as a string as follows {pId, x, y} for each row, each row separated by \n. The moves are returned in order of play (i.e. first move will be first row returned etc.). Using this we can evaluate how many moves have been taken (i.e. the number of rows), the last player to take a move (pId of the final row), plus all the moves taken to date.
+ * The method returns "ERROR-NOMOVES" if no moves have yet been made for that game, or "ERROR-DB" if unable to talk to the DB or DBMS.
+ */
+ @WebMethod(operationName = "getBoard")
+ public String getBoard(@WebParam(name = "gid") int gid) {
+ String sqlCmd = "SELECT pId, x, y FROM moves WHERE gId = " + gid + " ORDER BY played ASC;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOMOVES";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Returns the state of the game.
+ * @param gid the game id of the game whose state we wish to check.
+ * @return -1 (as a string) if waiting for a second player to join, 0 (as a string) if the game is in progress, 1 (as a string) if player 1 has won,
+ * 2 (as a string) if player 2 has won, 3 (as a string) if a draw, or "ERROR-NOGAME" if a game matching the game id cannot be found, or "ERROR-DB" if
+ * unable to talk to the DB or DBMS.
+ */
+ @WebMethod(operationName = "getGameState")
+ public String getGameState(@WebParam(name = "gid") int gid) {
+ String sqlCmd = "SELECT gamestate FROM games WHERE autokey = " + gid + ";";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOGAME";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Sets the state of a game.
+ * @param gid the game id of the game whose state we wish to set.
+ * @param gstate the state we wish to set the game to.
+ * @return 1 (as a string) if successful, "ERROR-NOGAME" if unable to find a game matching gid, "ERROR-DB" if unable to talk the the DB or DBMS.
+ */
+ @WebMethod(operationName = "setGameState")
+ public String setGameState(@WebParam(name = "gid") int gid, @WebParam(name = "gstate") int gstate) {
+ String sqlCmd = "UPDATE games SET gamestate = " + gstate + " WHERE autokey = " + gid + ";";
+ try {
+ String result = dao.update(sqlCmd);
+ if(result.equals("UPDATED 1 ROWS.")) {
+ return "1";
+ } else {
+ return "ERROR-NOGAME";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Checks a particular square in a game to see if it has been or can be taken.
+ * @param x the columns position of the square.
+ * @param y the row position of the square.
+ * @param gid the game we are playing/checking.
+ * @return 1 (as a string) if the square is taken, 0 (as a string) if the square is available, "ERROR-DB" if there is a problem talking to the DB or DBMS.
+ */
+ @WebMethod(operationName = "checkSquare")
+ public String checkSquare(@WebParam(name = "x") int x, @WebParam(name = "y") int y, @WebParam(name = "gid") int gid) {
+ String sqlCmd = "SELECT COUNT(*) FROM moves WHERE x = " + x + " AND y = " + y + " AND ";
+ sqlCmd += " gId = " + gid + ";";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ return result;
+ } catch (Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Takes a square in a particular game for a particular player.
+ * @param x the column position of the square.
+ * @param y the row position of the square.
+ * @param gid the game we are playing.
+ * @param pid the user id of the player taking the square.
+ * @return 1 (as a string) if successful, 0 (as a string) if unsuccessful, "ERROR-TAKEN" if the square is unavailable, "ERROR-DB" if there is a problem
+ * talking to the DB or DBMS, "ERROR" if there is a general error.
+ */
+ @WebMethod(operationName = "takeSquare")
+ public String takeSquare(@WebParam(name = "x") int x, @WebParam(name = "y") int y, @WebParam(name = "gid") int gid, @WebParam(name = "pid") int pid) {
+ int count = Integer.parseInt(checkSquare(x, y, gid));
+ String flag = "";
+ switch(count) {
+ case 1:
+ flag = "ERROR-TAKEN";
+ break;
+ case 0:
+ String sqlCmd = "INSERT INTO moves VALUES(default, " + pid + ", " + x + ", " + y;
+ sqlCmd += ", default, " + gid + ");";
+ try {
+ String result = dao.insert(sqlCmd);
+ if(result.equals("INSERTED 1 ROWS.")) {
+ flag = "1";
+ } else {
+ flag = "0";
+ }
+ } catch(Exception e) {
+ flag = "ERROR-DB";
+ }
+ break;
+ default:
+ flag = "ERROR";
+ }
+ return flag;
+ }
+
+ /**
+ * Used to see if the game is over or not, and who has won if it is over.
+ * @param gid the game id of the game we are checking.
+ * @return 0 (as a string) if the game hasn’t been won but can continue to be played, 1 (as a string) if player 1 has won,
+ * 2 (as a string) if player 2 has won, or 3 (as a string) if the game is a draw. The method will return “ERROR-RETRIEVE” if there is an issue
+ * getting details about the game, “ERROR-NOGAME” if no game can be found matching the gid, “ERROR-DB” if there is a problem accessing the DB or DBMS.
+ */
+ @WebMethod(operationName = "checkWin")
+ public String checkWin(@WebParam(name = "gid") int gid) {
+ String result = getBoard(gid);
+ int winner = 0;
+ if(result.length() > 0) {
+ String[] rows = result.split("\n");
+ int num_moves = rows.length;
+ int[][] table = new int[3][3];
+ for(int a = 0; a < 3; a++) {
+ for(int b = 0; b < 3; b++) {
+ table[a][b] = 0;
+ }
+ }
+ for(int i = 0; i < num_moves; i++) {
+ String[] cells = rows[i].split(",");
+ int pid = Integer.parseInt(cells[0]);
+ int x = Integer.parseInt(cells[1]);
+ int y = Integer.parseInt(cells[2]);
+ table[x][y] = pid;
+ }
+
+ //check rows and cols
+ for(int t = 0; t < 3; t++) {
+ if(table[t][0] == table[t][1] && table[t][1] == table[t][2] && table[t][0] != 0) {
+ winner = table[t][0];
+ }
+ if(table[0][t] == table[1][t] && table[1][t] == table[2][t] && table[0][t] != 0) {
+ winner = table[0][t];
+ }
+ }
+
+ //Check diagonals
+ if(table[0][0] == table[1][1] && table[1][1] == table[2][2] && table[0][0] != 0) {
+ winner = table[0][0];
+ }
+ if(table[0][2] == table[1][1] && table[1][1] == table[2][0] && table[0][2] != 0) {
+ winner = table[0][2];
+ }
+
+ if(winner > 0) {
+ try {
+ // check is winner p1 or p2;
+ String sqlCmd = "SELECT * FROM games WHERE autokey = " + gid + ";";
+ String gDetails = dao.retrieve(sqlCmd);
+ if(gDetails.length() > 0) {
+ String[] details = gDetails.split(",");
+ if(details.length > 0) {
+ int p1 = Integer.parseInt(details[1]);
+ int p2 = Integer.parseInt(details[2]);
+ if(winner == p1) {
+ return "1";
+ } else {
+ return "2";
+ }
+ } else {
+ return "ERROR-RETRIEVE";
+ }
+ } else {
+ return "ERROR-RETRIEVE";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ } else {
+ if(num_moves < 9) {
+ return "0";
+ } else {
+ return "3";
+ }
+ }
+ } else {
+ return "ERROR-NOGAME";
+ }
+ }
+
+ /**
+ * Used to remove un-started games from the DB.
+ * @param gid the game id of the game you wish to remove.
+ * @param uid the user id of the person making the request (can only delete games you created).
+ * @return If the game has already started or the user is not the creator of the game, the method returns “ERROR-GAMESTARTED”,
+ * otherwise it returns 1 (as a string). The method returns “ERROR-DB” if it cannot access the DBMS.
+ */
+ @WebMethod(operationName = "deleteGame")
+ public String deleteGame(@WebParam(name = "gid") int gid, @WebParam(name = "uid") int uid) {
+ String sqlCmd = "SELECT COUNT(*) FROM games WHERE autokey = " + gid + " AND p1 = ";
+ sqlCmd += uid + " AND p2 IS NULL;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.equals("1")) {
+ sqlCmd = "DELETE FROM games WHERE autokey = " + gid + ";";
+ result = dao.remove(sqlCmd);
+ return "1";
+ } else {
+ return "ERROR-GAMESTARTED";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Used to show games you have created but that have not yet started.
+ * @param uid the user id of the player making the request.
+ * @return If the method is successful it returns a string as follows {{g.autokey, u.username, g.started}\n}*. If unsuccessful, the method returns
+ * “ERROR-NOGAMES” if it can find no games, or “ERROR-DB” if it cannot access the DBMS.
+ */
+ @WebMethod(operationName = "showMyOpenGames")
+ public String showMyOpenGames(@WebParam(name = "uid") int uid) {
+ String sqlCmd = "SELECT g.autokey, u.username, g.started FROM games g, users u WHERE g.p1 = " + uid + " AND g.p2 IS NULL AND g.p1 = u.autokey ORDER BY g.started ASC;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOGAMES";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Retrieves all games the user has played/is playing.
+ * @param uid the user id of the player making the request.
+ * @return If successful it returns a string as follows {{g.autokey, h.username, o.username, g.started}\n}*. h.username and o.username are the
+ * usernames of player 1 and player 2 respectively. If unsuccessful, the method returns “ERROR-NOGAMES” if it can find no games, or “ERROR-DB”
+ * if it cannot access the DBMS.
+ */
+ @WebMethod(operationName = "showAllMyGames")
+ public String showAllMyGames(@WebParam(name = "uid") int uid) {
+ String sqlCmd = "SELECT g.autokey, h.username, o.username, g.started FROM games g, users h, users o WHERE (g.p1 = " + uid + " OR g.p2 = " + uid + ") AND g.p1 = h.autokey AND g.p2 = o.autokey ORDER BY g.started ASC;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOGAMES";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Used to generate the content for a league table.
+ * @return If successful it returns a string as follows {{g.autokey, h.username, o.username, g.gamestate, g.started}\n}*. h.username and o.username
+ * are the usernames of player 1 and player 2 respectively. If unsuccessful, the method returns “ERROR-NOGAMES” if it can find no games, or “ERROR-DB”
+ * if it cannot access the DBMS.
+ */
+ @WebMethod(operationName = "leagueTable")
+ public String leagueTable() {
+ String sqlCmd = "SELECT g.autokey, h.username, o.username, g.gamestate, g.started FROM games g, users h, users o WHERE g.p1 = h.autokey AND g.p2 = o.autokey ORDER BY g.started ASC;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOGAMES";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * The list of open games (those with a p1 but no p2).
+ * @return If successful it returns a string as follows {{g.autokey, h.username, g.started}\n}*. h.username is the usernames of the player who started
+ * the game. If unsuccessful, the method returns “ERROR-NOGAMES” if it can find no games, or “ERROR-DB” if it cannot access the DBMS.
+ */
+ @WebMethod(operationName = "showOpenGames")
+ public String showOpenGames() {
+ String sqlCmd = "SELECT g.autokey, h.username, g.started FROM games g, users h WHERE g.p2 IS NULL AND g.p1 = h.autokey ORDER BY g.started ASC;";
+ try {
+ String result = dao.retrieve(sqlCmd);
+ if(result.length() > 0) {
+ return result;
+ } else {
+ return "ERROR-NOGAMES";
+ }
+ } catch(Exception e) {
+ return "ERROR-DB";
+ }
+ }
+
+ /**
+ * Closes the connection to the database (before exiting the application).
+ */
+ @WebMethod(operationName = "closeConnection")
+ public void closeConnection() {
+ dao.close();
+ }
+}
diff --git a/TicTacToeWS/src/main/resources/META-INF/persistence.xml b/TicTacToeWS/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
+ <!-- Define Persistence Unit -->
+ <persistence-unit name="my_persistence_unit">
+
+ </persistence-unit>
+</persistence>
diff --git a/TicTacToeWS/src/main/webapp/WEB-INF/beans.xml b/TicTacToeWS/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
+ bean-discovery-mode="all">
+</beans>
+\ No newline at end of file
diff --git a/TicTacToeWS/src/main/webapp/WEB-INF/glassfish-web.xml b/TicTacToeWS/src/main/webapp/WEB-INF/glassfish-web.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
+<!--
+ Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+-->
+<glassfish-web-app error-url="">
+ <class-loader delegate="true"/>
+ <jsp-config>
+ <property name="keepgenerated" value="true">
+ <description>Keep a copy of the generated servlet class' java code.</description>
+ </property>
+ </jsp-config>
+</glassfish-web-app>
diff --git a/TicTacToeWS/src/main/webapp/WEB-INF/web.xml b/TicTacToeWS/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
+ version="6.0">
+ <session-config>
+ <session-timeout>
+ 30
+ </session-timeout>
+ </session-config>
+</web-app>
diff --git a/TicTacToeWS/src/main/webapp/index.html b/TicTacToeWS/src/main/webapp/index.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>TicTacToe Web Service</title>
+ <meta http-equiv="refresh" content="0; url=TicTacToeWebService?Tester" />
+ </head>
+</html>