Assignment

Assignment Brief:

Develop a multi-threaded client-server application to allow users to share drawings andillustrations using a virtual whiteboard. The application will allow users to send chat messages
to one another and to synchronously send drawings and paint actions to other users. Theapplication will need to trap drawing events using an event handler, and pipe these events
across the network using a custom network protocol. The network protocol will need to handle
simple paint events using the pencil tool, pallette changes using the pallette tool box as well as
image rotation and image zoom functions. Two samples are given below.

Part A – Chat Application 20%

  1. Develop a client-server application to allow users to send chat messages between other
    connected clients. Build on the functionality of laboratory 3 session group exercises.
    Part B – White Board Application 35%:
  1. Use JavaFX Canvas and develop a client-server application to allow simple drawcommands such as:
    ·Line
    ·Pen
    ·Circle/Oval
    ·Rectangle
    to be piped across the network using a custom network protocol. Allow user tochange colourwhile drawing.

Part C – User Interface 25%:

  • Develop the user-interface illustrated above using appropriate JavaFX componentssuch as Stage, Scene, Canvas, Buttons, TextField, TextArea and appropriate containersuch as Pane, BorderPane, VBox, HBox, GridPane and FlowPane etc.

Part D – Build User Guide 10%:

  1. Build user guide for your application. Which must contain screenshots of all Scenes(windows) with briefexplanation. You can submit either Microsoft Word file or pdf as
    user guide.

Part E – Advanced Feature Set 10%:

Note: Implement at-least one of the following advanced feature.
1. Develop extra code to allow a user to select regions of the whiteboard and to flip / rotate
this region.
2. Develop extra code to allow a user to copy and paste different sections of the whiteboard.
3. Develop code to allow the shared white board to be saved to the server.
4. Develop code to allow user to add images to drawing.
5. Re-implement network protocol using Remote Method Invocation in addition toNetwork Sockets

Solution 

ChatPanel.java 

importjava.awt.*;

importjava.awt.event.*;

importjavax.swing.*;

public class ChatPanel extends JPanel {

// Otherclass objects

JTextFieldtf;

JTextArea ta;

JLabel um;

FrameDemo container;

publicChatPanel() {}

publicChatPanel(final FrameDemo container) {

// Variable Declarations

this.container = container;

setLayout(new BorderLayout());

ta = new JTextArea();

ta.setEditable(false);

JScrollPanetasp = new JScrollPane(ta);

um = new JLabel(“Your conversation will appear below:”);

um.setForeground(new java.awt.Color(0, 0, 255));

um.setToolTipText(“Type your message in the given field below and press enter to send”);

tf = new JTextField();

tf.setToolTipText(“Type your message and press enter”);

tf.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

String text = tf.getText();

tf.setText(“”);

finalStringMessagesm = new StringMessage();

sm.setMessage(text);

container.sendMessage(sm);

tf.setToolTipText(“”);

}

});

add(tf, BorderLayout.SOUTH);

add(um, BorderLayout.NORTH);

add(tasp, BorderLayout.CENTER);

}

// Functions and Dimensions

public void appendMessage(String m) {

ta.append(m + “\n”);

}

public Dimension getPreferredSize() {

return new Dimension(450, 100);

}

public Dimension getMinimumSize() {

return new Dimension(450, 100);

}

} 

ControlPanel.java

 importjava.awt.event.*;

importjavax.swing.*;

public class ControlPanel extends JPanel {

// Variable Declarations

JButton b1, b2, b3, b4, b5, b6, b7, b8, b9, b10;

FrameDemo container;

ChatPanelcp;

DrawPaneldp;

publicControlPanel(FrameDemofd, ChatPanel cp1, DrawPanel dp1) {

container = fd;

cp = cp1;

dp = dp1;

b1 = new JButton(“Connect”);

b2 = new JButton(“Disconnect”);

b3 = new JButton(“Login”);

b4 = new JButton(“Clear”);

b5 = new JButton(“Send Drawing”);

b6 = new JButton(“Save-Chat”);

b7 = new JButton(“Load-Chat”);

b8 = new JButton(“Color”);

b9 = new JButton(“Reset Color”);

b10 = new JButton(“Draw Color”);

b1.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.connect();

}

});

b2.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.close();

}

});

b3.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

finalStringMessagesm = new StringMessage();

String urname;

urname = JOptionPane.showInputDialog(“Enter username:”);

if (urname != null) {

sm.setMessage(urname);

container.sendMessage(sm);

b3.setVisible(false);

b2.setVisible(true);

b4.setVisible(true);

b5.setVisible(true);

b6.setVisible(true);

b7.setVisible(true);

b8.setVisible(true);

b9.setVisible(true);

b10.setVisible(true);

cp.setVisible(true);

dp.setVisible(true);

container.SP_ONLINE.setVisible(true);

container.online.setVisible(true);

}

}

});

b4.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.clear();

}

});

b5.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

LineMessage lm = new LineMessage();

lm.setLineMessage(container.dp.linelist);

container.sendMessage(lm);

}

});

b6.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.savechat();

}

});

b7.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.loadchat();

}

});

b8.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.ccolor();

}

});

b9.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.rcolor();

}

});

b10.addActionListener(new ActionListener() {

public void actionPerformed(ActionEventae) {

container.dcolor();

}

});

add(b1);

add(b2);

add(b3);

add(b4);

add(b5);

add(b6);

add(b7);

add(b8);

add(b9);

add(b10);

}

} 

DataObject.java 

public class DataObject {

private String message;

publicDataObject() {}

publicDataObject(String message) {

setMessage(message);

}

public void setMessage(String message) {

this.message = message;

}

public String getMessage() {

return message;

}

} 

DrawPanel.java 

importjava.awt.*;

importjava.awt.event.*;

importjavax.swing.*;

importjava.util.*;

public class DrawPanel extends JPanel

implementsMouseMotionListener, MouseListener {

ArrayList<Line>linelist;

intlastX, lastY;

FrameDemo container;

publicDrawPanel() {}

publicDrawPanel(final FrameDemo container) {

setBackground(Color.WHITE);

linelist = new ArrayList<Line>();

addMouseMotionListener(this);

addMouseListener(this);

this.container = container;

setForeground(Color.red);

}

public void mouseMoved(MouseEvent me) {}

 

public void mouseDragged(MouseEvent me) {

intendX = me.getX();

intendY = me.getY();

Line line = new Line(lastX, lastY, endX, endY);

linelist.add(line);

lastX = endX;

lastY = endY;

repaint();

}

public void mouseEntered(MouseEvent me) {}

public void mouseExited(MouseEvent me) {}

public void mousePressed(MouseEvent me) {

lastX = me.getX();

lastY = me.getY();

}

public void mouseReleased(MouseEvent me) {}

public void mouseClicked(MouseEvent me) {}

public void paintComponent(Graphics g) {

super.paintComponent(g);

Iterator<Line> it = linelist.iterator();

while (it.hasNext()) {

Line current = it.next();

g.drawLine(current.getStartX(), current.getStartY(),

current.getEndX(), current.getEndY());

}

// LineMessage lm = new LineMessage();

// lm.setMessage(linelist);

// container.sendMessage(lm);

// g.drawString(“Painted on JPanel”,100,100);

}

public Dimension getPreferredSize() {

return new Dimension(450, 100);

}

public Dimension getMinimumSize() {

return new Dimension(450, 100);

}

} 

FrameDemo.java

importjava.awt.*;

importjavax.swing.*;

import java.io.*;

import java.net.*;

importjava.util.*;

importjava.awt.event.*;

importjava.util.logging.Level;

importjava.util.logging.Logger;

importjavax.swing.border.Border;

public class FrameDemo extends JFrame implements Runnable {

// LoginPanellp;

ChatPanelcp;

DrawPaneldp;

ControlPanelconp;

public static JPanel container = new JPanel();

JList online;

JScrollPane SP_ONLINE = new JScrollPane();

boolean connected;

Socket s;

ObjectOutputStreamoos;

ObjectInputStreamois;

publicFrameDemo() {}

publicFrameDemo(String s) {

super(s);

online = new JList();

online.addMouseListener(new MouseAdapter() {

public void mouseClicked(MouseEventevt) {

JList online = (JList)evt.getSource();

if (evt.getClickCount() == 2) {

int index = online.getSelectedIndex();

JOptionPane

.showMessageDialog(null, “You Clicked Twice!” + index);

}

else if (evt.getClickCount() == 3) {

int index = online.locationToIndex(evt.getPoint());

JOptionPane

.showMessageDialog(null,

“You Clicked Thrice!” + index);

}

}

});

online.setForeground(new java.awt.Color(0, 0, 255));

SP_ONLINE            .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

SP_ONLINE

.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

SP_ONLINE.setViewportView(online);

SP_ONLINE.setBounds(350, 90, 130, 180);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

cp = new ChatPanel(this);

dp = new DrawPanel(this);

conp = new ControlPanel(this, cp, dp);

container.setLayout(new BorderLayout());

container.add(cp, BorderLayout.WEST);

container.add(dp, BorderLayout.EAST);

container.add(SP_ONLINE, BorderLayout.CENTER);

getContentPane().add(container, BorderLayout.CENTER);

getContentPane().add(conp, BorderLayout.SOUTH);

// Display the window.

cp.setVisible(false);

dp.setVisible(false);

setSize(1000, 500);

setLocationRelativeTo(null);

conp.b2.setVisible(false);

conp.b3.setVisible(false);

conp.b4.setVisible(false);

conp.b5.setVisible(false);

conp.b6.setVisible(false);

conp.b7.setVisible(false);

conp.b8.setVisible(false);

conp.b9.setVisible(false);

conp.b10.setVisible(false);

dp.setVisible(false);

SP_ONLINE.setVisible(false);

setVisible(true);

conp.b1.setForeground(Color.blue);

conp.b2.setForeground(Color.blue);

conp.b3.setForeground(Color.blue);

conp.b4.setForeground(Color.blue);

conp.b5.setForeground(Color.blue);

conp.b6.setForeground(Color.blue);

conp.b7.setForeground(Color.blue);

conp.b8.setForeground(Color.blue);

conp.b9.setForeground(Color.blue);

conp.b10.setForeground(Color.blue);

SP_ONLINE.setForeground(Color.blue);

cp.ta.setForeground(Color.blue);

dp.setForeground(Color.black);

}

/// ———————————

public void setConnected(boolean c) {

connected = c;

}

publicbooleanisConnected() {

return connected;

}

public void connect() {

setConnected(true);

System.out.println(“Should connect now . . . “);

try {

s = new Socket(“localhost”,6969);

oos = new ObjectOutputStream(s.getOutputStream());

new Thread(this).start();

System.out.println(“Connected . . . “);

conp.b3.setVisible(true);

conp.b1.setVisible(false);

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

public void close() {

setConnected(false); // should send last message so others

// can update user list

// and remove self from shared arralist

// of handlers

try {

oos.writeObject(“remove”);

oos.flush();

oos.close();

s.close();

JOptionPane.showMessageDialog(null, “You disconnected!”);

System.out.println(“Disconnected . . . “);

System.exit(0);

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

public void run() {

try {

ois = new ObjectInputStream(s.getInputStream());

for (;;) {

Object o = receiveMessage();

if (o != null) {

if (o.toString().contains(“#?!”)) {

String TEMP1 = o.toString().substring(3);

TEMP1 = TEMP1.replace(“[“, “”);

TEMP1 = TEMP1.replace(“]”, “”);

String[] CurrentUsers = TEMP1.split(“,”);

online.setListData(CurrentUsers);

}

else if (o instanceof String) {

cp.appendMessage((String)o);

}

else if (o instanceofStringMessage) {

StringMessagesm = (StringMessage)o;

String s = (String)sm.getMessage();

System.out.println(s);

cp.ta.append(s + ” has joined” + “\n”);

}

else if (o instanceofArrayList) {

ArrayList<Line> message;

message = (ArrayList)o;

dp.linelist = message;

dp.repaint();

}

else if (o instanceofUserMessage) {

}

}

else {

break;

}

}

}

catch (FileNotFoundException e) {

System.out.println(e.getMessage());

}

catch (IOException e) {

System.out.println(“IO Exception: ” + e.getMessage());

}

finally {

try {

ois.close();

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

public void ccolor() {

conp.b1.setForeground(Color.darkGray);

conp.b2.setForeground(Color.GREEN);

conp.b3.setForeground(Color.yellow);

conp.b4.setForeground(Color.RED);

conp.b5.setForeground(Color.blue);

conp.b6.setForeground(Color.MAGENTA);

conp.b7.setForeground(Color.cyan);

conp.b8.setForeground(Color.red);

conp.b9.setForeground(Color.orange);

conp.b10.setForeground(Color.blue);

SP_ONLINE.setForeground(Color.pink);

cp.ta.setForeground(Color.yellow);

dp.setForeground(Color.BLUE);

Border border = BorderFactory.createLineBorder(Color.BLACK);

cp.ta

.setBorder(BorderFactory.createCompoundBorder(border, BorderFactory

.createEmptyBorder(10, 10, 10, 10)));

}

public void dcolor() {

String cc;

cc = JOptionPane.showInputDialog(“Enter message:”);

switch (cc) {

case “red”:

dp.setForeground(Color.red);

break;

case “blue”:

dp.setForeground(Color.blue);

break;

case “green”:

dp.setForeground(Color.green);

break;

case “yellow”:

dp.setForeground(Color.yellow);

break;

case “pink”:

dp.setForeground(Color.pink);

break;

case “orange”:

dp.setForeground(Color.orange);

break;

default:

dp.setForeground(Color.black);

break;

}

}

public void rcolor() {

conp.b1.setForeground(Color.blue);

conp.b2.setForeground(Color.blue);

conp.b3.setForeground(Color.blue);

conp.b4.setForeground(Color.blue);

conp.b5.setForeground(Color.blue);

conp.b6.setForeground(Color.blue);

conp.b7.setForeground(Color.blue);

conp.b8.setForeground(Color.blue);

conp.b9.setForeground(Color.blue);

conp.b10.setForeground(Color.blue);

SP_ONLINE.setForeground(Color.blue);

cp.ta.setForeground(Color.blue);

dp.setForeground(Color.red);

cp.ta.setBorder(BorderFactory.createEtchedBorder());

}

public void savechat() {

try {

PrintWritertextout = new PrintWriter(“Log.txt”);

FileOutputStream out = new FileOutputStream(“DrawLog.txt”);

ObjectOutputStreamoout = new ObjectOutputStream(out);

textout.print(cp.ta.getText());

oout.writeObject(dp.linelist);

textout.close();

oout.flush();

}

catch (IOException e) {

System.out.println(e);

}

}

public void loadchat() {

try {

Object myObject;

BufferedReaderbr = new BufferedReader(new FileReader(“Log.txt”));

ObjectInputStreamois =

newObjectInputStream(new FileInputStream(“DrawLog.txt”));

myObject = (Object)ois.readObject();

ArrayList<Line> message;

message = (ArrayList)myObject;

dp.linelist = message;

dp.repaint();

String line = null;

cp.ta.setText(“”);

while ((line = br.readLine()) != null) {

cp.ta.append(line);

}

}

catch (IOException e) {

System.out.println(e.getMessage());

}

catch (ClassNotFoundException ex) {

Logger.getLogger(FrameDemo.class.getName()).log(Level.SEVERE, null,

ex);

}

}

final public void sendMessage(Object o) {

if (isConnected()) {

try {

if (o instanceofLineMessage) {

System.out.println(“LineMessage written to stream”);

dp.setVisible(true);

oos.writeObject(o);

oos.flush();

}

else {

oos.writeObject(o);

oos.flush();

}

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

public Object receiveMessage() {

Object obj = null;

try {

obj = ois.readObject();

}

catch (IOException e) {

System.out.println(“End of stream.”);

}

catch (ClassNotFoundException e) {

System.out.println(e.getMessage());

}

returnobj;

}

public void clear() {

dp.linelist = new ArrayList<Line>();

dp.repaint();

cp.ta.setText(“”);

}

private static void createAndShowGUI() {

FrameDemo frame = new FrameDemo(“Chat System with Shared Whiteboard”);

}

public static void main(String[] args) {

// Schedule a job for the event-dispatching thread:

// creating and showing this application’s GUI.

javax.swing.SwingUtilities.invokeLater(new Runnable() {

public void run() {

createAndShowGUI();

}

});

}

} 

MessageContainer.java 

import java.io.*;

importjava.util.*;

abstract public class MessageContainer {

abstract public void setLineMessage(Object message);

abstract public Object getLineMessage();

}

classStringMessage extends DataObject implements Serializable {

String message;

public void setMessage(String message) {

this.message = (String)message;

}

public String getMessage() {

return message;

}

}

classUserMessage extends DataObject implements Serializable {

String message;

public void setMessage(String message) {

this.message = (String)message;

}

public String getMessage() {

return message;

}

}

classLineMessage extends MessageContainer implements Serializable {

ArrayList<Line> message;

public void setLineMessage(Object message) {

this.message = (ArrayList)message;

}

public Object getLineMessage() {

return message;

}

}

class Line implements Serializable {

intstartx, starty, endx, endy;

public Line() {}

public Line(intsx, intsy, int ex, intey) {

setStartX(sx);

setStartY(sy);

setEndX(ex);

setEndY(ey);

}

public void setStartX(intsx) {

startx = sx;

}

public void setStartY(intsy) {

starty = sy;

}

public void setEndX(int ex) {

endx = ex;

}

public void setEndY(intey) {

endy = ey;

}

publicintgetStartX() {

returnstartx;

}

publicintgetStartY() {

returnstarty;

}

publicintgetEndX() {

returnendx;

}

publicintgetEndY() {

returnendy;

}

} 

ThreadedObjectServer.java 

importjava.util.*;

import java.io.*;

import java.net.*;

public class ThreadedObjectServer {

public static void main(String[] args) {

ArrayList<ThreadedObjectHandler> handlers =

newArrayList<ThreadedObjectHandler>();

try {

ServerSocket s = new ServerSocket(6969);

for (;;) {

Socket incoming = s.accept();

System.out.println(“Client connected from:”

+ incoming.getLocalAddress().getHostName());

newThreadedObjectHandler(incoming, handlers).start();

}

}

catch (Exception e) {

System.out.println(e);

}

}

}

classThreadedObjectHandler extends Thread {

public static ArrayList<Socket>ConnectionArray = new ArrayList<>();

public static ArrayList<String>CurrentUsers = new ArrayList<>();

Object broadcastobject, writeobject, myObject = null;

private final Socket incoming;

ArrayList<ThreadedObjectHandler> handlers;

ObjectInputStream in;

ObjectOutputStream out;

publicThreadedObjectHandler(Socket incoming,

ArrayList<ThreadedObjectHandler> handlers) {

this.incoming = incoming;

this.handlers = handlers;

handlers.add(this);

}

public synchronized void broadcast(Object obj) {

Iterator<ThreadedObjectHandler> it = handlers.iterator();

while (it.hasNext()) {

ThreadedObjectHandler current = it.next();

try {

current.out.writeObject(obj);

current.out.reset();

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

public void run() {

try {

String username;

String s;

in = new ObjectInputStream(incoming.getInputStream());

out = new ObjectOutputStream(incoming.getOutputStream());

ConnectionArray.add(incoming);

StringMessageuname = (StringMessage)in.readObject();

username = (String)uname.getMessage();

CurrentUsers.add(username);

broadcast(username + “: ” + “joined the chat”);

for (;;) {

broadcast(“#?!” + CurrentUsers);

myObject = in.readObject();

if (myObjectinstanceofStringMessage) {

StringMessagesm = (StringMessage)myObject;

s = (String)sm.getMessage();

broadcastobject = username + “: ” + s;

}

else if ((myObject.toString().contains(“remove”))) {

broadcast(username + “: ” + “left the chat”);

CurrentUsers.remove(username);

broadcastobject = (“#?!” + CurrentUsers);

}

else if (myObjectinstanceofLineMessage) {

ArrayList<Line> message;

LineMessage lm = (LineMessage)myObject;

message = (ArrayList)lm.getLineMessage();

broadcastobject = message;

broadcast(username + “: ” + “wrote on the whitebaord”);

}

broadcast(broadcastobject);

}

}

catch (Exception e) {

System.out.println(e);

}

finally {

handlers.remove(this);

try {

in.close();

out.close();

incoming.close();

}

catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

}