Add CT5106 Software Engineering II

This commit is contained in:
2023-12-07 01:59:40 +00:00
parent f20dc766ef
commit eb94d02f16
132 changed files with 3695 additions and 0 deletions

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="assignment6" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="assignment6" options="-endorseddirs &quot;$PROJECT_DIR$/target/endorsed&quot;" />
</option>
</component>
</project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK" />
</project>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>assignment6</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
<filteredResources>
<filter>
<id>1700926764939</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -0,0 +1,5 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=false

View File

@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=disabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=17

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -0,0 +1,21 @@
<?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>9.1-web</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_j2eeVersion>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>gfv610ee9</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
<org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>ide</org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>
<netbeans.hint.jdkPlatform>JDK_17</netbeans.hint.jdkPlatform>
</properties>
</project-shared-configuration>

View File

@ -0,0 +1,76 @@
<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.mycompany</groupId>
<artifactId>assignment6</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>assignment6-1.0-SNAPSHOT</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
<jakartaee>10.0.0</jakartaee>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakartaee}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakartaee}</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,13 @@
package com.mycompany.assignment6;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
/**
* Configures JAX-RS for the application.
* @author Juneau
*/
@ApplicationPath("resources")
public class JAXRSConfiguration extends Application {
}

View File

@ -0,0 +1,20 @@
package com.mycompany.assignment6.resources;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
/**
*
* @author
*/
@Path("javaee8")
public class JavaEE8Resource {
@GET
public Response ping(){
return Response
.ok("ping")
.build();
}
}

View File

@ -0,0 +1,26 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package model;
/**
*
* @author andrew
*/
public class User {
private String username;
private String forum; // the forum to which the user belongs
public User(String username, String forum) {
this.username = username;
this.forum = forum;
}
// getters and setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getForum() { return forum; }
public void setForum(String forum) { this.forum = forum; }
}

View File

@ -0,0 +1,110 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package websocket;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.spi.JsonProvider;
import jakarta.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import model.User;
/**
*
* @author andrew
*/
@ApplicationScoped
public class UserSessionHandler {
// contains the sessions connected
private final Set<Session> sessions = new HashSet<>();
// key = session id, value = forum name
private final HashMap<String, String> sessionForums = new HashMap<>();
// key = forum name, value = posts on that forum
private final HashMap<String, ArrayList<String>> forumPosts = new HashMap<>();
// method to update a forum
public void updateForum(String forum, String message) {
// add the forum to forumPosts if it's not already there
forumPosts.putIfAbsent(forum, new ArrayList<>());
// add message to forumPosts
forumPosts.get(forum).add(message);
// build a json object to send to the connected sessions containing all the update information
JsonProvider provider = JsonProvider.provider();
JsonObjectBuilder jsonObj = provider.createObjectBuilder()
.add("action", "update")
.add("posts", forumPosts.get(forum).get(forumPosts.get(forum).size() -1));
// update all connected sessions with the json object
sendToAllConnectedSessionsByForum(jsonObj.build(), forum);
}
public void addSession(Session session) {
sessions.add(session);
}
// method to add a user session to a particular forum
public void addSessionToForum(Session session, User user) {
sessionForums.put(session.getId(), user.getForum());
JsonObject joinMessage = createJoinMessage(user);
sendToSession(session, joinMessage);
}
public void removeSession(Session session) { sessions.remove(session); }
private JsonObject createJoinMessage(User user) {
JsonProvider provider = JsonProvider.provider();
JsonObjectBuilder joinMessage = provider.createObjectBuilder()
.add("action", "join")
.add("username", user.getUsername())
.add("forum", user.getForum());
// if the forum is already in forumPosts, add its posts to the joinMessage
if (forumPosts.containsKey(user.getForum())) {
JsonArrayBuilder posts = provider.createArrayBuilder(forumPosts.get(user.getForum()));
joinMessage.add("posts", posts);
}
// otherwise, add an empty posts array to the joinMessage
else {
JsonArrayBuilder postArr = provider.createArrayBuilder();
joinMessage.add("posts", postArr);
}
return joinMessage.build();
}
// method to send data to all the sessions connected to a given forum
private void sendToAllConnectedSessionsByForum(JsonObject jsonObj, String forum) {
// loop over each connected session
for (Session session : sessions) {
// if the session's id corresponds to the given forum, send the data to the session
// Check if the session's id is in sessionForums
if (sessionForums.get(session.getId()).equals(forum)) {
sendToSession(session, jsonObj);
}
}
}
private void sendToSession(Session session, JsonObject message) {
try {
session.getBasicRemote().sendText(message.toString());
} catch (IOException e) {
System.out.println("session could not be reached");
}
}
}

View File

@ -0,0 +1,63 @@
package websocket;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.json.JsonReader;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.User;
/**
*
* @author andrew
*/
@ApplicationScoped
@ServerEndpoint("/actions")
public class UserWebSocketServer {
@Inject
private UserSessionHandler sessionHandler;
@OnOpen
public void open(Session session) {
sessionHandler.addSession(session);
}
@OnClose
public void close(Session session) {
sessionHandler.removeSession(session);
}
@OnError
public void onError(Throwable error) { Logger.getLogger(UserWebSocketServer.class.getName()).log(Level.SEVERE, null, error); }
@OnMessage
public void handleMessage(String message, Session session) {
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
// if action is "join", instantiate a new user
if ("join".equals(jsonMessage.getString("action"))) {
User user = new User(jsonMessage.getString("username"), jsonMessage.getString("forum"));
sessionHandler.addSession(session);
sessionHandler.addSessionToForum(session, user);
}
// if action is "update", update the specified forum with the message
if ("update".equals(jsonMessage.getString("action"))) {
sessionHandler.updateForum(jsonMessage.getString("forum"), jsonMessage.getString("message"));
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<!-- Define Persistence Unit -->
<persistence-unit name="my_persistence_unit">
</persistence-unit>
</persistence>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all">
</beans>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<!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">
<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>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Select Forum</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="websocket.js"></script>
</head>
<body>
<form id="forumForm">
<h1>Choose the Forum you want to join</h1>
<p>username</p>
<input type="text" id="username">
<select id="forum">
<option value="Politics">Politics</option>
<option value="Technology">Technology</option>
<option value="Sport">Sport</option>
<option value="Music">Music</option>
<option value="Films">Films</option>
</select>
<input type="button" value="Join" onclick="formSubmit()">
</form>
<!-- div to contain the content of the forum pages -->
<div id="content"></div>
</body>
</html>

View File

@ -0,0 +1,81 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/JSP_Servlet/JavaScript.js to edit this template
*/
// socket for the session
var socket;
function onMessage(event) {
var data = JSON.parse(event.data);
// if the action is "join", create the forum on the index.html page
if (data.action === "join") {
document.getElementById("content").innerHTML =
"<h1>" + data.forum + "</h1><br>" +
"<textarea id='messagebox' readonly></textarea><br>" +
"<h2>Post a comment on the forum</h2>" +
"<input type='text' id='inputbox'>" +
// make the button always pass the correct forum and username to the onButtonClick method
"<button type='button' onclick='onButtonClick(`" + data.forum + "`,`" + data.username + "`)'>Post</button>";
var messagebox = document.getElementById("messagebox");
// looping over each post in the event data and appending it to the messagebox
for(let post of data.posts){
document.getElementById("messagebox").innerHTML += post + "\n";
}
}
// else if action is "update", update the textarea with the posts in the data object
else if (data.action === "update") {
document.getElementById("messagebox").innerHTML += data.posts + "\n";
}
}
// function that's ran when the post button is clicked
function onButtonClick(forum, username) {
var messageData = {
action: "update",
// data will be guaranteed to be defined if the button exists to be clicked, as it is only created in onMessage()
forum: forum,
// prepending the user's username onto the message for convenience
// since there is no real signing-in, we will never need to know who posted which message except for displaying it
message: username + ": " + document.getElementById("inputbox").value
};
socket.send(JSON.stringify(messageData));
// reset the inputbox to be empty
document.getElementById("inputbox").value = "";
}
function showForm(){ document.getElementById("forumForm").style.display = ""; }
function hideForm() { document.getElementById("forumForm").style.display = "none"; }
function formSubmit() {
// request to open a websocket with the server application
socket = new WebSocket("ws://localhost:8080/assignment6/actions");
// define the socket's onopen function
socket.onopen = () => {
// user data to send to the server
var user = {
action: "join",
username: document.getElementById("forumForm").elements["username"].value,
forum: document.getElementById("forumForm").elements["forum"].value
};
// hide the form and reset it
hideForm();
document.getElementById("forumForm").reset();
// send user data to the server to be instantiated
socket.send(JSON.stringify(user));
};
// set socket's onmessage function
socket.onmessage = onMessage;
}