Compare commits

...

5 Commits

Author SHA1 Message Date
Mars Ultor
646a0484fb Yo chat i'm cooked - 2 2025-03-24 12:23:33 -05:00
Mars Ultor
eca6d173f0 Yo chat i'm cooked 2025-03-24 11:59:25 -05:00
46057701ca Fixed stuff 12 2025-03-23 20:08:33 -05:00
3203801710 Fixed stuff 2025-03-23 20:08:10 -05:00
fe81a701d8 Fixed stuff 2025-03-23 20:02:18 -05:00
21 changed files with 401 additions and 18 deletions

15
.idea/runConfigurations/App.xml generated Normal file
View File

@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="App" type="Application" factoryName="Application" singleton="false" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="net.ayyalasomayajula.net.App" />
<module name="my-app" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="net.ayyalasomayajula.net.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@@ -0,0 +1 @@
<EFBFBD>

1
server/lock.lock Normal file
View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -0,0 +1 @@
<EFBFBD>

View File

@@ -118,9 +118,15 @@ public class Dashboard extends JFrame {
try {
while (true) {
// Read the next message from the server
Message receivedMessage = (Message) inputStream.readObject();
receivedMessages.add(receivedMessage);
updateMessageDisplay(receivedMessage); // Update the GUI with the new message
Object receivedMessage = inputStream.readObject();
if(receivedMessage instanceof Message) {
Message message = (Message) receivedMessage;
logger.info("Received Message response response: {}", message);
if(message.data().length == 0) {continue;}
receivedMessages.add(message);
updateMessageDisplay(message); // Update the GUI with the new message
}
}
} catch (IOException | ClassNotFoundException e) {
logger.error("Error while listening for messages: {}", e.getMessage());

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.ayyalasomayajula.net.client.EHRGen">
<grid id="27dc6" binding="main" layout-manager="GridLayoutManager" row-count="13" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="652" height="1122"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="8d5d9" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Patient Name"/>
</properties>
</component>
<component id="4ee4a" class="javax.swing.JTextField" binding="patientNameValue">
<constraints>
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
<component id="ab11d" class="javax.swing.JLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="UUID"/>
</properties>
</component>
<component id="5123d" class="javax.swing.JTextField" binding="uuidVAlue">
<constraints>
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
<component id="aebca" class="javax.swing.JLabel">
<constraints>
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Medical Notes"/>
</properties>
</component>
<component id="47eac" class="javax.swing.JList" binding="medicalNotesList">
<constraints>
<grid row="5" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="2" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
</constraints>
<properties/>
</component>
<component id="713d6" class="javax.swing.JLabel">
<constraints>
<grid row="6" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Appointment Log"/>
</properties>
</component>
<component id="eb0a9" class="javax.swing.JList" binding="appointmentLogList">
<constraints>
<grid row="7" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="2" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
</constraints>
<properties/>
</component>
<component id="e9d6c" class="javax.swing.JLabel">
<constraints>
<grid row="8" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="XRAYs"/>
</properties>
</component>
<component id="c25a7" class="javax.swing.JList" binding="xrayList">
<constraints>
<grid row="9" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="2" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
</constraints>
<properties/>
</component>
<component id="ba8b7" class="javax.swing.JLabel">
<constraints>
<grid row="10" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="DOB"/>
</properties>
</component>
<component id="da3c9" class="javax.swing.JTextField" binding="textField3" default-binding="true">
<constraints>
<grid row="11" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
<component id="b5025" class="javax.swing.JTextField" binding="textField4" default-binding="true">
<constraints>
<grid row="11" column="3" row-span="1" col-span="2" vsize-policy="0" hsize-policy="7" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties/>
</component>
<component id="67949" class="javax.swing.JLabel">
<constraints>
<grid row="10" column="3" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="JoinDate"/>
</properties>
</component>
<component id="852d8" class="javax.swing.JButton" binding="insertButton" default-binding="true">
<constraints>
<grid row="12" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Insert"/>
</properties>
</component>
<component id="b3893" class="javax.swing.JButton" binding="updateButton" default-binding="true">
<constraints>
<grid row="12" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Update"/>
</properties>
</component>
</children>
</grid>
</form>

View File

@@ -0,0 +1,168 @@
package net.ayyalasomayajula.net.client;
import net.ayyalasomayajula.net.shared.Appointment;
import net.ayyalasomayajula.net.shared.Message;
import net.ayyalasomayajula.net.shared.MessageVariant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import net.ayyalasomayajula.net.shared.EHR;
/**
* A graphical user interface for viewing and managing an Electronic Health Record (EHR).
*/
public class EHRGen extends JFrame {
private static final Logger logger = LoggerFactory.getLogger(EHRGen.class);
private JTextField patientNameValue;
private JTextField uuidValue;
private JList<String> medicalNotesList;
private JList<String> appointmentLogList;
private JList<String> xrayList;
private JButton updateButton;
private JButton insertButton;
private JPanel main;
private final ObjectOutputStream os;
private final ObjectInputStream oi;
private final Socket connection;
private final ObjectOutputStream outputStream;
private EHR currentEHR; // Stores the current EHR instance
/**
* Constructs an EHRGen window with a given socket connection and EHR data.
*
* @param connection the socket connection to the server
* @param ehr the EHR object containing patient data
* @throws IOException if an I/O error occurs while creating the output stream
*/
public EHRGen(Socket connection, EHR ehr) throws IOException {
this.connection = connection;
this.currentEHR = ehr;
this.outputStream = new ObjectOutputStream(connection.getOutputStream());
setTitle("Electronic Health Record");
setContentPane(main);
setSize(600, 400);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
populateFields(); // Populate fields with EHR data if available
insertButton.addActionListener(e -> insertEHR());
updateButton.addActionListener(e -> updateEHR());
os = new ObjectOutputStream(connection.getOutputStream());
oi = new ObjectInputStream(connection.getInputStream());
}
/**
* Populates the UI fields with data from the current EHR.
*/
private void populateFields() {
if (currentEHR != null) {
patientNameValue.setText(currentEHR.getPatientName());
uuidValue.setText(currentEHR.getUuid().toString());
// Populate lists
populateList(medicalNotesList, currentEHR.getMedicalNotes());
populateList(appointmentLogList, currentEHR.getAppointmentLog().stream().map(Appointment::toString).toList());
populateList(xrayList, currentEHR.getXrays().stream().map(Path::toString).toList());
}
}
/**
* Populates a JList with data.
*
* @param list the JList to populate
* @param data the list of strings to display in the JList
*/
private void populateList(JList<String> list, List<String> data) {
if (data != null) {
list.setListData(data.toArray(new String[0]));
}
}
/**
* Converts a date string from "yyyy-MM-dd" format to "dd/MM/yyyy" format.
*
* @param inputDate the date string in "yyyy-MM-dd" format
* @return the formatted date string in "dd/MM/yyyy" format, or the original string if parsing fails
*/
private String convertDate(String inputDate) {
try {
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat ehrFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = inputFormat.parse(inputDate);
return ehrFormat.format(date);
} catch (ParseException e) {
logger.error("Date conversion failed: {}", e.getMessage());
return inputDate; // Return original in case of error
}
}
/**
* Handles the insertion of a new EHR record.
* Displays an error message if required fields are missing.
*/
private void insertEHR() {
if (!fieldsPopulated()) {
JOptionPane.showMessageDialog(this, "All fields must be populated before inserting.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Insertion logic to be implemented
dispose();
}
/**
* Handles updating an existing EHR record.
* Displays an error message if required fields are missing.
*/
private void updateEHR() {
if (!fieldsPopulated()) {
JOptionPane.showMessageDialog(this, "All fields must be populated before updating.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Update logic to be implemented
dispose();
}
/**
* Checks if all required fields are populated.
*
* @return true if all required fields contain data, false otherwise
*/
private boolean fieldsPopulated() {
return !patientNameValue.getText().isEmpty() &&
!uuidValue.getText().isEmpty() &&
medicalNotesList.getModel().getSize() > 0 &&
appointmentLogList.getModel().getSize() > 0 &&
xrayList.getModel().getSize() > 0;
}
/**
* Launches the EHRGen window in a separate UI thread.
*
* @param connection the socket connection to the server
* @param ehr the EHR object to display
*/
public static void showEHR(Socket connection, EHR ehr) {
SwingUtilities.invokeLater(() -> {
try {
new EHRGen(connection, ehr).setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

View File

@@ -178,16 +178,11 @@ public class ServerDaemon implements Runnable {
private Message handleMessage(Message in) throws IOException {
switch (in.messageVariant()) {
case GET: {
// Format of GET query:
// <asset_type> <asset_id> | asset types: EHR, XRAY | asset id: uuid field or the path
// Define regex pattern with capture groups
Pattern pattern = Pattern.compile("^(EHR|XRAY) (.+)$");
Matcher matcher = pattern.matcher(in.messageQuery());
if (matcher.matches()) {
String assetType = matcher.group(1); // Captures EHR or XRAY
String assetId = matcher.group(2); // Captures UUID or path
String assetType = matcher.group(1);
String assetId = matcher.group(2);
logger.debug("Asset Type: {}", assetType);
logger.debug("Asset ID: {}", assetId);
@@ -195,16 +190,14 @@ public class ServerDaemon implements Runnable {
case "EHR":
logger.info("EHR caught");
EHR found = EHRUtils.searchClosestEHR(assetId, Path.of(basePath));
if (found == null) return new Message(MessageVariant.SET, "ERROR: EHR not found.", 5, new byte[]{});
return new Message(MessageVariant.SET, "", 5, SerializationUtils.toBytes(found));
case "XRAY":
logger.info("XRAY caught");
// Construct full file path for XRAY asset
Path xrayFilePath = Path.of(basePath, assetId);
File xrayFile = xrayFilePath.toFile();
// Check if the file exists and is a valid file
if (xrayFile.exists() && xrayFile.isFile()) {
// Read the file into a byte array and return it
try (FileInputStream fis = new FileInputStream(xrayFile)) {
byte[] fileBytes = fis.readAllBytes();
return new Message(MessageVariant.SET, "", 5, fileBytes);
@@ -222,8 +215,41 @@ public class ServerDaemon implements Runnable {
}
break;
}
case INSERT: {
try {
EHR ehr = (EHR) SerializationUtils.fromBytes(in.data());
Path ehrDirPath = Path.of(basePath, "patients");
EHRUtils.writeEHRToFile(ehr, ehrDirPath);
return new Message(MessageVariant.SET, "SUCCESS: EHR inserted.", 5, new byte[]{});
} catch (IOException | ClassNotFoundException e) {
logger.error("Error inserting EHR: {}", e.getMessage());
return new Message(MessageVariant.SET, "ERROR: Failed to insert EHR.", 5, new byte[]{});
}
}
case UPSERT: {
try {
EHR ehr = (EHR) SerializationUtils.fromBytes(in.data());
Path ehrDirPath = Path.of(basePath, "patients");
EHR existingEHR = EHRUtils.readEHRFromFile(ehrDirPath, ehr.getUuid());
if (existingEHR != null) {
logger.info("Updating existing EHR with UUID: {}", ehr.getUuid());
} else {
logger.info("Inserting new EHR with UUID: {}", ehr.getUuid());
}
EHRUtils.writeEHRToFile(ehr, ehrDirPath);
return new Message(MessageVariant.SET, "SUCCESS: EHR upserted.", 5, new byte[]{});
} catch (IOException | ClassNotFoundException e) {
logger.error("Error upserting EHR: {}", e.getMessage());
return new Message(MessageVariant.SET, "ERROR: Failed to upsert EHR.", 5, new byte[]{});
}
}
}
return new Message(MessageVariant.SET, "THROW;", 5, new byte[]{});
}
}

View File

@@ -1,5 +1,6 @@
package net.ayyalasomayajula.net.shared;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.UUID;
@@ -9,7 +10,7 @@ import java.util.UUID;
* @author Krishna Ayyalasomayajula
* @version 1.0
*/
public record Appointment(UUID uuid, UUID patient, LocalDateTime time, boolean attendance, String description) {
public record Appointment(UUID uuid, UUID patient, LocalDateTime time, boolean attendance, String description) implements Serializable {
/**
* Evaluates whether the allotted time has already passed.
* @return boolean object, true if date time is past
@@ -17,4 +18,21 @@ public record Appointment(UUID uuid, UUID patient, LocalDateTime time, boolean a
public boolean isPast() {
return time.isBefore(LocalDateTime.now());
}
@Override
/**
* Returns a string representation of the Appointment record.
* The format includes the UUID, patient ID, time, attendance status, and description.
*
* @return A string containing the appointment details.
*/
public String toString() {
return "Appointment{" +
"uuid=" + uuid +
", patient=" + patient +
", time=" + time +
", attendance=" + attendance +
", description='" + description + '\'' +
'}';
}
}

View File

@@ -3,6 +3,7 @@ package net.ayyalasomayajula.net.shared;
import net.ayyalasomayajula.net.shared.Appointment;
import net.ayyalasomayajula.net.shared.Message;
import java.io.Serializable;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.ArrayList;
@@ -17,7 +18,7 @@ import java.util.UUID;
* @author Krishna Ayyalasomayajula
* @version 1.0
*/
public class EHR {
public class EHR implements Serializable {
private String patientName;
private UUID uuid;
private List<String> medicalNotes;

View File

@@ -1,12 +1,15 @@
package net.ayyalasomayajula.net.shared;
import java.io.Serializable;
/**
* Encapsulates the socket message objects using a record.
*
* @author Krishna Ayyalasomayajula
* @version 1.0
*/
public record Message(MessageVariant messageVariant, String messageQuery, int timeoutSeconds, byte[] data) {
public record Message(MessageVariant messageVariant, String messageQuery, int timeoutSeconds, byte[] data) implements Serializable {
/**
* Constructor for Message record.
* @author Krishna Ayyalasomayajula

View File

@@ -1,6 +1,8 @@
package net.ayyalasomayajula.net.shared;
public enum MessageVariant{
import java.io.Serializable;
public enum MessageVariant implements Serializable {
GET("GET"), SET("SET"), UPSERT("UPSERT"), INSERT("INSERT");