Spent most of this last week switching between work on developing a Check() hierarchy for validating xml importation, and a minesweeper app for my android app programming class. The former project I can't discuss too much, only to say that I need to learn how to work with registry design patterns, and am not quite clear where the hierarchy is going to go. The latter I am finding much more difficult than it seemed at first.
Apparently, most everyone is treating the actual setup of the boxes manually instead of programattically, putting their positioning information into the xml by hand. The way I envision it is more automated (but in turn, more difficult to figure out how to do), with the number and size of the boxes adapting to user input.
Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts
Wednesday, May 11, 2011
Wednesday, May 4, 2011
Dev Diary May 4th, 2011
So, I got a job working as an intern working for a company by the name of Data In Motion as of this last Monday. Not much to say about it as of yet except that there's a ton to the job, and I am currently... whelmed at the tasks ahead. That is to say, it's certainly daunting, but I think if I take it one piece at a time (like one of my favorite Johnny Cash songs) I'll get to understanding it, and be able to make myself useful to my employers. For the time being, they are doing a lot more for me than I am for them, and it is currently just a hope to be a good return on that investment.
All that having been said, I probably won't be sharing my code from work-related projects here on my blog, unless given explicit permission to do so. I am also starting a class for developing android applications, and may share some of the toy programs from that class (albeit if it looks even marginally profitable I'd be keeping mum). So that's the situation if you were wondering when my next interesting tidbit of code would appear.
And now I'm off to spend the rest of the evening getting used to some new equipment. And to read up on marker, visitor, and singleton design patterns. On a complete sidenote, I should remind myself to strongly suggest to my professors here at Westminster to implement a class focused on design patterns.
All that having been said, I probably won't be sharing my code from work-related projects here on my blog, unless given explicit permission to do so. I am also starting a class for developing android applications, and may share some of the toy programs from that class (albeit if it looks even marginally profitable I'd be keeping mum). So that's the situation if you were wondering when my next interesting tidbit of code would appear.
And now I'm off to spend the rest of the evening getting used to some new equipment. And to read up on marker, visitor, and singleton design patterns. On a complete sidenote, I should remind myself to strongly suggest to my professors here at Westminster to implement a class focused on design patterns.
Labels:
Computer Science,
CS,
Dev Diaries,
Java
Monday, November 15, 2010
An n^n algorithm (or a surefire way to freeze up your memory lickety-split)
So one of my friends and I were talking about algorithm analysis and tried to think up a quick and dirty n^n algorithm (that is, one which grows on a more than factorial order) and this is what we came up with. Be forewarned: Calling this function with an argument of more than 30 is likely to eat all your memory (on the school computer we tried it on we got a BSOD. Wheeeeee!)
void int sum(int n)
{
//base case
if(n == 0)
return 1;
int sum = 0;
for(int i = 0; i < n; i++)
sum += sum(i);
return sum;
}
This is like the fibonacci series on crack (in terms of the call hierarchy), though it ends up falling into a pattern of simply doubling. You get a slightly more interesting pattern by switching the initialization of sum from 0 to n, but the main point here is to maximize the number of operations in as little code as possible without generating an infinite loop.
void int sum(int n)
{
//base case
if(n == 0)
return 1;
int sum = 0;
for(int i = 0; i < n; i++)
sum += sum(i);
return sum;
}
This is like the fibonacci series on crack (in terms of the call hierarchy), though it ends up falling into a pattern of simply doubling. You get a slightly more interesting pattern by switching the initialization of sum from 0 to n, but the main point here is to maximize the number of operations in as little code as possible without generating an infinite loop.
Labels:
C,
C++,
Computer Science,
CS,
Java
Wednesday, June 16, 2010
Iterated Circles - Mod of Sierpenski Square program
/* CMPT 300X Chaos Working with Fractals: Iterated Circle
*
* rewrite of Sierpinski Square code to iterate a circular fractal
Author: Daniel Tanner
*Note you can mess around with the code here a bit to avoid printing circles inside each other to generate a different fractal pattern (which I kinda like better but... eh).
*/
import javax.swing.JFrame; //imports for the frame
import java.awt.*; //imports the colour
import java.awt.Graphics; //imports the graphics
import java.util.Random; // imports the random class for random colour
import javax.swing.JPanel;
public class IteratedCircle extends JPanel
{
public Graphics g;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
public static void main (String[]args)
{
JFrame SS = new JFrame("Drawing with Recursion");
SS.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SS.setVisible(true); //Show the first drawing.
IteratedCircle S = new IteratedCircle(); //call default constructor (not written);
SS.setBackground(Color.BLACK);
SS.add(S);
SS.setSize(500, 500); //(width ,height ) */
//new SFrame(); // call to the frame, program
}
public void paint(Graphics g)
{
this.g = g;
// start recursion with first call to draw square
drawCircle( getWidth() / 2, getHeight() / 2, getWidth() / 4);
}
private void drawCircle ( int x, int y ,int radius)
{
if (radius > 3) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawCircle((int)(x + radius * .75), y, radius / 2); //draws and fill the square, bigger one
drawCircle((int)(x - radius * .75), y, radius / 2);
drawCircle(x, (int)(y + radius * .75), radius / 2);
drawCircle(x, (int)(y - radius * .75), radius / 2);
//repaint();
}
}
private void drawUpCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawDownCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawLeftCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawRightCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
//repaint();
}
}
}//end of class
*
* rewrite of Sierpinski Square code to iterate a circular fractal
Author: Daniel Tanner
*Note you can mess around with the code here a bit to avoid printing circles inside each other to generate a different fractal pattern (which I kinda like better but... eh).
*/
import javax.swing.JFrame; //imports for the frame
import java.awt.*; //imports the colour
import java.awt.Graphics; //imports the graphics
import java.util.Random; // imports the random class for random colour
import javax.swing.JPanel;
public class IteratedCircle extends JPanel
{
public Graphics g;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
public static void main (String[]args)
{
JFrame SS = new JFrame("Drawing with Recursion");
SS.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SS.setVisible(true); //Show the first drawing.
IteratedCircle S = new IteratedCircle(); //call default constructor (not written);
SS.setBackground(Color.BLACK);
SS.add(S);
SS.setSize(500, 500); //(width ,height ) */
//new SFrame(); // call to the frame, program
}
public void paint(Graphics g)
{
this.g = g;
// start recursion with first call to draw square
drawCircle( getWidth() / 2, getHeight() / 2, getWidth() / 4);
}
private void drawCircle ( int x, int y ,int radius)
{
if (radius > 3) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawCircle((int)(x + radius * .75), y, radius / 2); //draws and fill the square, bigger one
drawCircle((int)(x - radius * .75), y, radius / 2);
drawCircle(x, (int)(y + radius * .75), radius / 2);
drawCircle(x, (int)(y - radius * .75), radius / 2);
//repaint();
}
}
private void drawUpCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawDownCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawLeftCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
drawLeftCircle((int)(x - radius * .75), y, radius / 2);
//repaint();
}
}
private void drawRightCircle( int x, int y ,int radius)
{
if (radius > 1) //control when to stop: when size is 2x2 pixels
{
g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
g.drawRoundRect(x - radius / 2, y - radius / 2, radius, radius, radius * radius, radius / 2);
drawUpCircle(x, (int)(y + radius * .75), radius / 2);
drawRightCircle((int)(x + radius * .75), y, radius / 2);
drawDownCircle(x, (int)(y - radius * .75), radius / 2);
//repaint();
}
}
}//end of class
Labels:
Chaos Theory,
Computer Science,
CS,
Java,
Shinies
The Dragon Curve
/*
* Author: Daniel Tanner
* Dragon Curve Program
*
* This program runs a recursive program to keep replacing a given
* string such as "f" with "f+h" and "h" with "f-h",
* and after a certain number of said recursions, translates that
* string into a physical display. The result is known as the
* Dragon Curve.
*/
import java.awt.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DragonCurve extends JPanel {
public Graphics g1;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
public static double degToRad(int deg) { //degree to radian conversion
return deg * Math.PI / 180;
}
//paint method is automatically called for us by tree recursive (will be called 4 times! Once for each call to drawFractal
public void paint(final Graphics g) {
this.g1 = g;
g1.setColor(c);
int numRecursions = 14;
double startAngle = degToRad(0);
int distance = 3;
//First call to do the drawing, this call draws the trunk: start(X,Y) at base, angle 0, len calculated)
drawCurve(getWidth() / 2, getHeight() / 2, numRecursions, startAngle, distance); //first call
//System.out.println("in paint, number of calls to drawFractal is " + count +"\n");
}
//dragon curve method -- starts at the middle and applies rules to curve
public void drawCurve(int x0, int y0, int numRecursions, double startAngle, int distance)
{
String dragonString = "f";
for(int i = 0; i < numRecursions; i++)
{
String tempString = "";
for(int j = 0; j < dragonString.length(); j++)
{ //replace the f with f + h
if(dragonString.charAt(j) == 'f')
tempString += "f-h";
else if(dragonString.charAt(j) == 'h')
tempString += "f+h";
else
tempString += dragonString.charAt(j);
}
dragonString = tempString;
}
System.out.println(dragonString);
//now draw the image
for(int index = 0; index < dragonString.length(); index++)
{
if(dragonString.charAt(index) == 'f' || dragonString.charAt(index) == 'h')
{
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
int x1 = (int)(x0 + distance * Math.cos(startAngle));
int y1 = (int)(y0 + distance * Math.sin(startAngle));
g1.drawLine(x0, y0, x1, y1);
x0 = x1; y0 = y1;
}
else if(dragonString.charAt(index) == 'g')
{
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
int x1 = (int)(x0 + distance * Math.cos(startAngle));
int y1 = (int)(y0 + distance * Math.sin(startAngle));
x0 = x1; y0 = y1;
}
else if(dragonString.charAt(index) == '+')
startAngle = startAngle - Math.PI / 2.0;
else if(dragonString.charAt(index) == '-')
startAngle = startAngle + Math.PI / 2.0;
}
}
//main method
public static void main(String args[]) {
// System.out.println("count begins with at " + count +"\n");
JFrame FF = new JFrame("Drawing the Dragon Curve");
FF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FF.setVisible(true); //Show the first drawing.
DragonCurve F = new DragonCurve(); //call default constructor (not written); F is the Tree.
FF.setBackground(Color.BLACK);
FF.add(F);
FF.setSize(1000, 1000); //(width 1200,height 1000)
}
}
* Author: Daniel Tanner
* Dragon Curve Program
*
* This program runs a recursive program to keep replacing a given
* string such as "f" with "f+h" and "h" with "f-h",
* and after a certain number of said recursions, translates that
* string into a physical display. The result is known as the
* Dragon Curve.
*/
import java.awt.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DragonCurve extends JPanel {
public Graphics g1;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
public static double degToRad(int deg) { //degree to radian conversion
return deg * Math.PI / 180;
}
//paint method is automatically called for us by tree recursive (will be called 4 times! Once for each call to drawFractal
public void paint(final Graphics g) {
this.g1 = g;
g1.setColor(c);
int numRecursions = 14;
double startAngle = degToRad(0);
int distance = 3;
//First call to do the drawing, this call draws the trunk: start(X,Y) at base, angle 0, len calculated)
drawCurve(getWidth() / 2, getHeight() / 2, numRecursions, startAngle, distance); //first call
//System.out.println("in paint, number of calls to drawFractal is " + count +"\n");
}
//dragon curve method -- starts at the middle and applies rules to curve
public void drawCurve(int x0, int y0, int numRecursions, double startAngle, int distance)
{
String dragonString = "f";
for(int i = 0; i < numRecursions; i++)
{
String tempString = "";
for(int j = 0; j < dragonString.length(); j++)
{ //replace the f with f + h
if(dragonString.charAt(j) == 'f')
tempString += "f-h";
else if(dragonString.charAt(j) == 'h')
tempString += "f+h";
else
tempString += dragonString.charAt(j);
}
dragonString = tempString;
}
System.out.println(dragonString);
//now draw the image
for(int index = 0; index < dragonString.length(); index++)
{
if(dragonString.charAt(index) == 'f' || dragonString.charAt(index) == 'h')
{
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
int x1 = (int)(x0 + distance * Math.cos(startAngle));
int y1 = (int)(y0 + distance * Math.sin(startAngle));
g1.drawLine(x0, y0, x1, y1);
x0 = x1; y0 = y1;
}
else if(dragonString.charAt(index) == 'g')
{
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
int x1 = (int)(x0 + distance * Math.cos(startAngle));
int y1 = (int)(y0 + distance * Math.sin(startAngle));
x0 = x1; y0 = y1;
}
else if(dragonString.charAt(index) == '+')
startAngle = startAngle - Math.PI / 2.0;
else if(dragonString.charAt(index) == '-')
startAngle = startAngle + Math.PI / 2.0;
}
}
//main method
public static void main(String args[]) {
// System.out.println("count begins with at " + count +"\n");
JFrame FF = new JFrame("Drawing the Dragon Curve");
FF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FF.setVisible(true); //Show the first drawing.
DragonCurve F = new DragonCurve(); //call default constructor (not written); F is the Tree.
FF.setBackground(Color.BLACK);
FF.add(F);
FF.setSize(1000, 1000); //(width 1200,height 1000)
}
}
Labels:
Chaos Theory,
Computer Science,
CS,
Java,
Shinies
Chaos Program - Julia Orbits
/*Author: Daniel Tanner
*Julia Orbits Display Program
*This program displays all the orbit diagrams for a given julia set
*(which the user can change by clicking on the viewing window)
*
*Basically displaying a line following the points when you take a
*pair of starting values for a complex number 'c' (IE, x + yi), plug
*it into the function (z^2 + c) where z is the starting point, and then
*plug the result back into the function until the result is > 2
*/
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class JuliaOrbit extends JPanel implements MouseListener, WindowListener {
public Graphics g1;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
private double cX = .360248, cY = .100376;
public static double degToRad(int deg)
{ //degree to radian conversion
return deg * Math.PI / 180;
}
//paint method is automatically called for us by tree recursive (will be called 4 times! Once for each call to drawFractal
public void paint(Graphics g)
{
this.g1 = g;
g1.setColor(c);
double initX, initY;
//First call to do the drawing, this call draws the trunk: start(X,Y) at base, angle 0, len calculated)
for(initX = -2.0; initX <= 2.0; initX += 0.01)
{
for(initY = -2.0; initY <= 2.0; initY += 0.01)
{
drawJuliaOrbit(cX, cY, initX, initY); //first call
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
}
}
}
//dragon curve method -- starts at the middle and applies rules to curve
public void drawJuliaOrbit(double cX, double cY, double initX, double initY)
{
int m0 = (int)((initX + 1.0) * getWidth() / 2);
int n0 = (int)((1.0 - initY) * getHeight() / 2);
int iterations = 0;
double q = Math.sqrt(initX * initX + initY * initY);
while(q < 2 && iterations < 35)
{
iterations++;
double y1 = 2.0 * (initX * initY);
double x1 = (initX * initX) + -(initY * initY);
initX = x1 + cX;
initY = y1 + cY;
int m1 = (int)((initX + 2.0) * getWidth() / 4);
int n1 = (int)((2.0 - initY) * getHeight() / 4);
g1.drawLine(m0, n0, m1, n1);
q = Math.sqrt(initX * initX + initY * initY);
m0 = m1; n0 = n1;
}
}
//main method
public static void main(String args[]) {
// System.out.println("count begins with at " + count +"\n");
JFrame FF = new JFrame("Drawing the Julia Orbit");
FF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FF.setVisible(true); //Show the first drawing.
JuliaOrbit F = new JuliaOrbit(); //call default constructor (not written); F is the Tree.
FF.setBackground(Color.BLACK);
FF.addMouseListener(F);
FF.add(F);
FF.setSize(200, 200); //(width 1200,height 1000)
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e)
{
if(e.getButton() == MouseEvent.BUTTON1)
{
cX = Double.parseDouble(JOptionPane.showInputDialog("Enter a new cX value:"));
cY = Double.parseDouble(JOptionPane.showInputDialog("Enter a new cY value:"));
this.repaint();
}
}
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {
}
@Override
public void windowActivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowClosed(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowOpened(WindowEvent arg0) {
// TODO Auto-generated method stub
}
}
*Julia Orbits Display Program
*This program displays all the orbit diagrams for a given julia set
*(which the user can change by clicking on the viewing window)
*
*Basically displaying a line following the points when you take a
*pair of starting values for a complex number 'c' (IE, x + yi), plug
*it into the function (z^2 + c) where z is the starting point, and then
*plug the result back into the function until the result is > 2
*/
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class JuliaOrbit extends JPanel implements MouseListener, WindowListener {
public Graphics g1;
public Color c =Color.WHITE; // set colour to white to create the blanks
public Random r = new Random();
private double cX = .360248, cY = .100376;
public static double degToRad(int deg)
{ //degree to radian conversion
return deg * Math.PI / 180;
}
//paint method is automatically called for us by tree recursive (will be called 4 times! Once for each call to drawFractal
public void paint(Graphics g)
{
this.g1 = g;
g1.setColor(c);
double initX, initY;
//First call to do the drawing, this call draws the trunk: start(X,Y) at base, angle 0, len calculated)
for(initX = -2.0; initX <= 2.0; initX += 0.01)
{
for(initY = -2.0; initY <= 2.0; initY += 0.01)
{
drawJuliaOrbit(cX, cY, initX, initY); //first call
g1.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255))); //random colour (default is white)
}
}
}
//dragon curve method -- starts at the middle and applies rules to curve
public void drawJuliaOrbit(double cX, double cY, double initX, double initY)
{
int m0 = (int)((initX + 1.0) * getWidth() / 2);
int n0 = (int)((1.0 - initY) * getHeight() / 2);
int iterations = 0;
double q = Math.sqrt(initX * initX + initY * initY);
while(q < 2 && iterations < 35)
{
iterations++;
double y1 = 2.0 * (initX * initY);
double x1 = (initX * initX) + -(initY * initY);
initX = x1 + cX;
initY = y1 + cY;
int m1 = (int)((initX + 2.0) * getWidth() / 4);
int n1 = (int)((2.0 - initY) * getHeight() / 4);
g1.drawLine(m0, n0, m1, n1);
q = Math.sqrt(initX * initX + initY * initY);
m0 = m1; n0 = n1;
}
}
//main method
public static void main(String args[]) {
// System.out.println("count begins with at " + count +"\n");
JFrame FF = new JFrame("Drawing the Julia Orbit");
FF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FF.setVisible(true); //Show the first drawing.
JuliaOrbit F = new JuliaOrbit(); //call default constructor (not written); F is the Tree.
FF.setBackground(Color.BLACK);
FF.addMouseListener(F);
FF.add(F);
FF.setSize(200, 200); //(width 1200,height 1000)
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e)
{
if(e.getButton() == MouseEvent.BUTTON1)
{
cX = Double.parseDouble(JOptionPane.showInputDialog("Enter a new cX value:"));
cY = Double.parseDouble(JOptionPane.showInputDialog("Enter a new cY value:"));
this.repaint();
}
}
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {
}
@Override
public void windowActivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowClosed(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void windowOpened(WindowEvent arg0) {
// TODO Auto-generated method stub
}
}
Labels:
Chaos Theory,
Computer Science,
CS,
Java,
Shinies
Tuesday, April 13, 2010
Chat Server (final version)
/** Chat Server
Authors: Daniel J. Tanner and Jon Fidler
March 29th, 2010
CMPT 352 - Networking
This program implements the Spring 2010 Networking class' Chat Protocol
**/
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer
{
//constants & globals
public static final int PORT = 2222;
private static ChatServerSubject buffer = null;
public static void main(String[] args) throws java.io.IOException
{
//load everything up
buffer = new ChatServerSubject();
//Create socket
ServerSocket sock = null;
try
{
//establish socket
sock = new ServerSocket(PORT);
while(true)
{
Socket client = sock.accept();
//debug testing
InetAddress ipAddr = client.getInetAddress();
System.out.print(ipAddr.getHostAddress() + " : ");
System.out.println(client.getPort() + " connected.");
Thread worker = new Thread(new Connection(client, buffer));
worker.start();
}
}
//catch any errors opening sockets
catch(IOException ioe)
{
System.err.println(ioe);
System.exit(0);
}
finally
{
//close streams
if(sock != null)
sock.close();
}
}
//getUserList function - returns a pointer to the user List
public static Vector<String> getUserList() {return buffer.getUserList();}
}
/** ChatServerSubject object
-- implementation of the Subject class, containing the user list, an observer list, and the message buffer
-- This class will notify each child thread of the server whenever a change is made on either of these 2 objects.
Authors: Jon Fidler & Daniel Tanner
March 31st, 2010
CMPT 352 - Networking
*/
import java.util.*;
import java.net.*;
import java.awt.*;
public class ChatServerSubject extends Observable
{
//members
private Vector<String> userList;
private Vector<MessageObject> messageBuffer;
private String removedUser;
//flags
/* whatHappened flag = int representing the state of the object.
0 = nothing's changed
1 = user added
2 = user removed
3 = message added
*/
private int whatHappened;
//constructors
public ChatServerSubject()
{
userList = new Vector<String>();
messageBuffer = new Vector<MessageObject>();
removedUser = "NOBODY";
whatHappened = 0;
}
/** userList changing functions
*/
//add a user
public void addUser(String userName)
{
userList.add(userName);
//set flags
whatHappened = 1;
setChanged();
notifyObservers();
}
//remove a user from the list
public void removeUser(String userName)
{
removedUser = userName;
userList.remove(userName);
//set flags
whatHappened = 2;
setChanged();
notifyObservers();
}
//check if a user is on the list or not
public boolean userExists(String userName)
{
return userList.contains(userName);
}
//get user list
public Vector<String> getUserList(){return userList;}
//get the name of the user who just disconnected
public String getDCedUser() {return removedUser;}
//returns the last user on the list (most recently added user
public String getNewUser() {return userList.lastElement();}
/**Message Buffer functions
*/
//get message function
public MessageObject getMessage() {return messageBuffer.firstElement();}
//add message function
public void addMessage(MessageObject message)
{
messageBuffer.add(message);
whatHappened = 3;
setChanged();
notifyObservers();
}
//remove a message
public void removeMessage(MessageObject message)
{
messageBuffer.remove(message);
}
/* Flag checking functions*/
public boolean userAdded()
{
if(whatHappened == 1)
return true;
return false;
}
public boolean userRemoved()
{
if(whatHappened == 2)
return true;
return false;
}
public boolean messageAdded()
{
if(whatHappened == 3)
return true;
return false;
}
}
/** Connection Class for threaded Chat Server
Daniel Tanner & John Fidler
CMPT 352 - Computer Networking
March 29th, 2010
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class Connection implements Runnable
{
//create variables
private Socket client;
private ChatServerSubject buffer;
private Handler handler = new Handler();
public Connection(Socket client, ChatServerSubject buffer)
{
this.client = client;
this.buffer = buffer;
}
//Separate thread
public void run()
{
try
{
handler.process(client, buffer);
}
catch (java.io.IOException ioe)
{
System.err.println(ioe);
}
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionality implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*"))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
/**
BufferKeyEntry class
Contain fields to put into the key of the message buffer
The value will be the unformatted message
Members of the BufferEntry are as follows:
-Who sent the message (so we don't echo it back)
-A non-static counter which will tell us when all the threads have sent the message
so we know when to remove the message from our buffer.
-Who the message is to (* for broadcasts)
*/
/**
Authors: Daniel Tanner & Jon Fidler
March 29th, 2010
CMPT 352 - Networking
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class MessageObject
{
//create variables
private String toUser;
private String fromUser;
private int counter;
private String message;
//constructor
MessageObject()
{
counter = ChatServer.getUserList().size();
toUser = null;
fromUser = null;
message = null;
}
//copy constructor
MessageObject(MessageObject copy)
{
this.toUser = copy.toUser;
this.fromUser = copy.fromUser;
this.counter = copy.counter;
this.message = copy.message;
}
//Constructor with arguments
MessageObject(String toUser, String fromUser, String message)
{
counter = ChatServer.getUserList().size();
this.toUser = toUser;
this.fromUser = fromUser;
this.message = message;
}
//get functions
int getCounter() {return counter;}
String getToUser() {return toUser;}
String getFromUser() {return fromUser;}
String getMessage() {return message;}
//set functions
void setToUser(String toUser) {this.toUser = toUser;}
void setFromUser(String fromUser) {this.fromUser = fromUser;}
void setMessage(String message) {this.message = message;}
//viewed function - This function will decrement the counter
void viewed() {counter--;}
//equals function
boolean equals(MessageObject rhs)
{
if(toUser.equals(rhs.toUser) && fromUser.equals(rhs.fromUser) && counter == rhs.counter && message.equals(rhs.message))
return true;
else
return false;
}
}
Authors: Daniel J. Tanner and Jon Fidler
March 29th, 2010
CMPT 352 - Networking
This program implements the Spring 2010 Networking class' Chat Protocol
**/
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer
{
//constants & globals
public static final int PORT = 2222;
private static ChatServerSubject buffer = null;
public static void main(String[] args) throws java.io.IOException
{
//load everything up
buffer = new ChatServerSubject();
//Create socket
ServerSocket sock = null;
try
{
//establish socket
sock = new ServerSocket(PORT);
while(true)
{
Socket client = sock.accept();
//debug testing
InetAddress ipAddr = client.getInetAddress();
System.out.print(ipAddr.getHostAddress() + " : ");
System.out.println(client.getPort() + " connected.");
Thread worker = new Thread(new Connection(client, buffer));
worker.start();
}
}
//catch any errors opening sockets
catch(IOException ioe)
{
System.err.println(ioe);
System.exit(0);
}
finally
{
//close streams
if(sock != null)
sock.close();
}
}
//getUserList function - returns a pointer to the user List
public static Vector<String> getUserList() {return buffer.getUserList();}
}
/** ChatServerSubject object
-- implementation of the Subject class, containing the user list, an observer list, and the message buffer
-- This class will notify each child thread of the server whenever a change is made on either of these 2 objects.
Authors: Jon Fidler & Daniel Tanner
March 31st, 2010
CMPT 352 - Networking
*/
import java.util.*;
import java.net.*;
import java.awt.*;
public class ChatServerSubject extends Observable
{
//members
private Vector<String> userList;
private Vector<MessageObject> messageBuffer;
private String removedUser;
//flags
/* whatHappened flag = int representing the state of the object.
0 = nothing's changed
1 = user added
2 = user removed
3 = message added
*/
private int whatHappened;
//constructors
public ChatServerSubject()
{
userList = new Vector<String>();
messageBuffer = new Vector<MessageObject>();
removedUser = "NOBODY";
whatHappened = 0;
}
/** userList changing functions
*/
//add a user
public void addUser(String userName)
{
userList.add(userName);
//set flags
whatHappened = 1;
setChanged();
notifyObservers();
}
//remove a user from the list
public void removeUser(String userName)
{
removedUser = userName;
userList.remove(userName);
//set flags
whatHappened = 2;
setChanged();
notifyObservers();
}
//check if a user is on the list or not
public boolean userExists(String userName)
{
return userList.contains(userName);
}
//get user list
public Vector<String> getUserList(){return userList;}
//get the name of the user who just disconnected
public String getDCedUser() {return removedUser;}
//returns the last user on the list (most recently added user
public String getNewUser() {return userList.lastElement();}
/**Message Buffer functions
*/
//get message function
public MessageObject getMessage() {return messageBuffer.firstElement();}
//add message function
public void addMessage(MessageObject message)
{
messageBuffer.add(message);
whatHappened = 3;
setChanged();
notifyObservers();
}
//remove a message
public void removeMessage(MessageObject message)
{
messageBuffer.remove(message);
}
/* Flag checking functions*/
public boolean userAdded()
{
if(whatHappened == 1)
return true;
return false;
}
public boolean userRemoved()
{
if(whatHappened == 2)
return true;
return false;
}
public boolean messageAdded()
{
if(whatHappened == 3)
return true;
return false;
}
}
/** Connection Class for threaded Chat Server
Daniel Tanner & John Fidler
CMPT 352 - Computer Networking
March 29th, 2010
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class Connection implements Runnable
{
//create variables
private Socket client;
private ChatServerSubject buffer;
private Handler handler = new Handler();
public Connection(Socket client, ChatServerSubject buffer)
{
this.client = client;
this.buffer = buffer;
}
//Separate thread
public void run()
{
try
{
handler.process(client, buffer);
}
catch (java.io.IOException ioe)
{
System.err.println(ioe);
}
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionality implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*"))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
/**
BufferKeyEntry class
Contain fields to put into the key of the message buffer
The value will be the unformatted message
Members of the BufferEntry are as follows:
-Who sent the message (so we don't echo it back)
-A non-static counter which will tell us when all the threads have sent the message
so we know when to remove the message from our buffer.
-Who the message is to (* for broadcasts)
*/
/**
Authors: Daniel Tanner & Jon Fidler
March 29th, 2010
CMPT 352 - Networking
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class MessageObject
{
//create variables
private String toUser;
private String fromUser;
private int counter;
private String message;
//constructor
MessageObject()
{
counter = ChatServer.getUserList().size();
toUser = null;
fromUser = null;
message = null;
}
//copy constructor
MessageObject(MessageObject copy)
{
this.toUser = copy.toUser;
this.fromUser = copy.fromUser;
this.counter = copy.counter;
this.message = copy.message;
}
//Constructor with arguments
MessageObject(String toUser, String fromUser, String message)
{
counter = ChatServer.getUserList().size();
this.toUser = toUser;
this.fromUser = fromUser;
this.message = message;
}
//get functions
int getCounter() {return counter;}
String getToUser() {return toUser;}
String getFromUser() {return fromUser;}
String getMessage() {return message;}
//set functions
void setToUser(String toUser) {this.toUser = toUser;}
void setFromUser(String fromUser) {this.fromUser = fromUser;}
void setMessage(String message) {this.message = message;}
//viewed function - This function will decrement the counter
void viewed() {counter--;}
//equals function
boolean equals(MessageObject rhs)
{
if(toUser.equals(rhs.toUser) && fromUser.equals(rhs.fromUser) && counter == rhs.counter && message.equals(rhs.message))
return true;
else
return false;
}
}
Labels:
Computer Science,
CS,
Java,
Networking
Wednesday, March 31, 2010
Chat Server (Working for the most part)
/** ChatServerSubject object
-- implementation of the Subject class, containing the user list, an observer list, and the message buffer
-- This class will notify each child thread of the server whenever a change is made on either of these 2 objects.
Authors: Jon Fidler & Daniel Tanner
March 31st, 2010
CMPT 352 - Networking
*/
import java.util.*;
import java.net.*;
import java.awt.*;
public class ChatServerSubject extends Observable
{
//members
private Vector<String> userList;
private Vector<MessageObject> messageBuffer;
private String removedUser;
//flags
/* whatHappened flag = int representing the state of the object.
0 = nothing's changed
1 = user added
2 = user removed
3 = message added
*/
private int whatHappened;
//constructors
public ChatServerSubject()
{
userList = new Vector<String>();
messageBuffer = new Vector<MessageObject>();
removedUser = "NOBODY";
whatHappened = 0;
}
/** userList changing functions
*/
//add a user
public void addUser(String userName)
{
userList.add(userName);
//set flags
whatHappened = 1;
setChanged();
notifyObservers();
}
//remove a user from the list
public void removeUser(String userName)
{
removedUser = userName;
userList.remove(userName);
//set flags
whatHappened = 2;
setChanged();
notifyObservers();
}
//check if a user is on the list or not
public boolean userExists(String userName)
{
return userList.contains(userName);
}
//get user list
public Vector<String> getUserList(){return userList;}
//get the name of the user who just disconnected
public String getDCedUser() {return removedUser;}
//returns the last user on the list (most recently added user
public String getNewUser() {return userList.lastElement();}
/**Message Buffer functions
*/
//get message function
public MessageObject getMessage() {return messageBuffer.firstElement();}
//add message function
public void addMessage(MessageObject message)
{
messageBuffer.add(message);
whatHappened = 3;
setChanged();
notifyObservers();
}
//remove a message
public void removeMessage(MessageObject message)
{
messageBuffer.remove(message);
}
/* Flag checking functions*/
public boolean userAdded()
{
if(whatHappened == 1)
return true;
return false;
}
public boolean userRemoved()
{
if(whatHappened == 2)
return true;
return false;
}
public boolean messageAdded()
{
if(whatHappened == 3)
return true;
return false;
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
System.out.println("You've reached the broadcast method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
System.out.println("privateMessage method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "/n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionanility implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
System.out.println("your observers are being updated!");
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*") && !newMessage.getFromUser().equals(myUserName))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
/** Connection Class for threaded Chat Server
Daniel Tanner & John Fidler
CMPT 352 - Computer Networking
March 29th, 2010
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class Connection implements Runnable
{
//create variables
private Socket client;
private ChatServerSubject buffer;
private Handler handler = new Handler();
public Connection(Socket client, ChatServerSubject buffer)
{
this.client = client;
this.buffer = buffer;
}
//Separate thread
public void run()
{
try
{
handler.process(client, buffer);
}
catch (java.io.IOException ioe)
{
System.err.println(ioe);
}
}
}
/** Chat Server
Authors: Daniel J. Tanner and Jon Fidler
March 29th, 2010
CMPT 352 - Networking
This program implements the Spring 2010 Networking class' Chat Protocol
**/
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer
{
//constants & globals
public static final int PORT = 2222;
private static ChatServerSubject buffer = null;
public static void main(String[] args) throws java.io.IOException
{
//load everything up
buffer = new ChatServerSubject();
//Create socket
ServerSocket sock = null;
try
{
//establish socket
sock = new ServerSocket(PORT);
while(true)
{
Socket client = sock.accept();
//debug testing
InetAddress ipAddr = client.getInetAddress();
System.out.print(ipAddr.getHostAddress() + " : ");
System.out.println(client.getPort() + " connected.");
Thread worker = new Thread(new Connection(client, buffer));
worker.start();
}
}
//catch any errors opening sockets
catch(IOException ioe)
{
System.err.println(ioe);
System.exit(0);
}
finally
{
//close streams
if(sock != null)
sock.close();
}
}
//getUserList function - returns a pointer to the user List
public static Vector<String> getUserList() {return buffer.getUserList();}
}
/**
BufferKeyEntry class
Contain fields to put into the key of the message buffer
The value will be the unformatted message
Members of the BufferEntry are as follows:
-Who sent the message (so we don't echo it back)
-A non-static counter which will tell us when all the threads have sent the message
so we know when to remove the message from our buffer.
-Who the message is to (* for broadcasts)
*/
/**
Authors: Daniel Tanner & Jon Fidler
March 29th, 2010
CMPT 352 - Networking
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class MessageObject
{
//create variables
private String toUser;
private String fromUser;
private int counter;
private String message;
//constructor
MessageObject()
{
counter = ChatServer.getUserList().size();
toUser = null;
fromUser = null;
message = null;
}
//copy constructor
MessageObject(MessageObject copy)
{
this.toUser = copy.toUser;
this.fromUser = copy.fromUser;
this.counter = copy.counter;
this.message = copy.message;
}
//Constructor with arguments
MessageObject(String toUser, String fromUser, String message)
{
counter = ChatServer.getUserList().size();
this.toUser = toUser;
this.fromUser = fromUser;
this.message = message;
}
//get functions
int getCounter() {return counter;}
String getToUser() {return toUser;}
String getFromUser() {return fromUser;}
String getMessage() {return message;}
//set functions
void setToUser(String toUser) {this.toUser = toUser;}
void setFromUser(String fromUser) {this.fromUser = fromUser;}
void setMessage(String message) {this.message = message;}
//viewed function - This function will decrement the counter
void viewed() {counter--;}
//equals function
boolean equals(MessageObject rhs)
{
if(toUser.equals(rhs.toUser) && fromUser.equals(rhs.fromUser) && counter == rhs.counter && message.equals(rhs.message))
return true;
else
return false;
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
System.out.println("You've reached the broadcast method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
System.out.println("privateMessage method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "/n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionanility implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
System.out.println("your observers are being updated!");
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*") && !newMessage.getFromUser().equals(myUserName))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
-- implementation of the Subject class, containing the user list, an observer list, and the message buffer
-- This class will notify each child thread of the server whenever a change is made on either of these 2 objects.
Authors: Jon Fidler & Daniel Tanner
March 31st, 2010
CMPT 352 - Networking
*/
import java.util.*;
import java.net.*;
import java.awt.*;
public class ChatServerSubject extends Observable
{
//members
private Vector<String> userList;
private Vector<MessageObject> messageBuffer;
private String removedUser;
//flags
/* whatHappened flag = int representing the state of the object.
0 = nothing's changed
1 = user added
2 = user removed
3 = message added
*/
private int whatHappened;
//constructors
public ChatServerSubject()
{
userList = new Vector<String>();
messageBuffer = new Vector<MessageObject>();
removedUser = "NOBODY";
whatHappened = 0;
}
/** userList changing functions
*/
//add a user
public void addUser(String userName)
{
userList.add(userName);
//set flags
whatHappened = 1;
setChanged();
notifyObservers();
}
//remove a user from the list
public void removeUser(String userName)
{
removedUser = userName;
userList.remove(userName);
//set flags
whatHappened = 2;
setChanged();
notifyObservers();
}
//check if a user is on the list or not
public boolean userExists(String userName)
{
return userList.contains(userName);
}
//get user list
public Vector<String> getUserList(){return userList;}
//get the name of the user who just disconnected
public String getDCedUser() {return removedUser;}
//returns the last user on the list (most recently added user
public String getNewUser() {return userList.lastElement();}
/**Message Buffer functions
*/
//get message function
public MessageObject getMessage() {return messageBuffer.firstElement();}
//add message function
public void addMessage(MessageObject message)
{
messageBuffer.add(message);
whatHappened = 3;
setChanged();
notifyObservers();
}
//remove a message
public void removeMessage(MessageObject message)
{
messageBuffer.remove(message);
}
/* Flag checking functions*/
public boolean userAdded()
{
if(whatHappened == 1)
return true;
return false;
}
public boolean userRemoved()
{
if(whatHappened == 2)
return true;
return false;
}
public boolean messageAdded()
{
if(whatHappened == 3)
return true;
return false;
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
System.out.println("You've reached the broadcast method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
System.out.println("privateMessage method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "/n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionanility implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
System.out.println("your observers are being updated!");
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*") && !newMessage.getFromUser().equals(myUserName))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
/** Connection Class for threaded Chat Server
Daniel Tanner & John Fidler
CMPT 352 - Computer Networking
March 29th, 2010
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class Connection implements Runnable
{
//create variables
private Socket client;
private ChatServerSubject buffer;
private Handler handler = new Handler();
public Connection(Socket client, ChatServerSubject buffer)
{
this.client = client;
this.buffer = buffer;
}
//Separate thread
public void run()
{
try
{
handler.process(client, buffer);
}
catch (java.io.IOException ioe)
{
System.err.println(ioe);
}
}
}
/** Chat Server
Authors: Daniel J. Tanner and Jon Fidler
March 29th, 2010
CMPT 352 - Networking
This program implements the Spring 2010 Networking class' Chat Protocol
**/
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer
{
//constants & globals
public static final int PORT = 2222;
private static ChatServerSubject buffer = null;
public static void main(String[] args) throws java.io.IOException
{
//load everything up
buffer = new ChatServerSubject();
//Create socket
ServerSocket sock = null;
try
{
//establish socket
sock = new ServerSocket(PORT);
while(true)
{
Socket client = sock.accept();
//debug testing
InetAddress ipAddr = client.getInetAddress();
System.out.print(ipAddr.getHostAddress() + " : ");
System.out.println(client.getPort() + " connected.");
Thread worker = new Thread(new Connection(client, buffer));
worker.start();
}
}
//catch any errors opening sockets
catch(IOException ioe)
{
System.err.println(ioe);
System.exit(0);
}
finally
{
//close streams
if(sock != null)
sock.close();
}
}
//getUserList function - returns a pointer to the user List
public static Vector<String> getUserList() {return buffer.getUserList();}
}
/**
BufferKeyEntry class
Contain fields to put into the key of the message buffer
The value will be the unformatted message
Members of the BufferEntry are as follows:
-Who sent the message (so we don't echo it back)
-A non-static counter which will tell us when all the threads have sent the message
so we know when to remove the message from our buffer.
-Who the message is to (* for broadcasts)
*/
/**
Authors: Daniel Tanner & Jon Fidler
March 29th, 2010
CMPT 352 - Networking
*/
import java.net.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class MessageObject
{
//create variables
private String toUser;
private String fromUser;
private int counter;
private String message;
//constructor
MessageObject()
{
counter = ChatServer.getUserList().size();
toUser = null;
fromUser = null;
message = null;
}
//copy constructor
MessageObject(MessageObject copy)
{
this.toUser = copy.toUser;
this.fromUser = copy.fromUser;
this.counter = copy.counter;
this.message = copy.message;
}
//Constructor with arguments
MessageObject(String toUser, String fromUser, String message)
{
counter = ChatServer.getUserList().size();
this.toUser = toUser;
this.fromUser = fromUser;
this.message = message;
}
//get functions
int getCounter() {return counter;}
String getToUser() {return toUser;}
String getFromUser() {return fromUser;}
String getMessage() {return message;}
//set functions
void setToUser(String toUser) {this.toUser = toUser;}
void setFromUser(String fromUser) {this.fromUser = fromUser;}
void setMessage(String message) {this.message = message;}
//viewed function - This function will decrement the counter
void viewed() {counter--;}
//equals function
boolean equals(MessageObject rhs)
{
if(toUser.equals(rhs.toUser) && fromUser.equals(rhs.fromUser) && counter == rhs.counter && message.equals(rhs.message))
return true;
else
return false;
}
}
/**
Daniel Tanner & Jon Fidler
CMPT 352 - Computer Networking
March 29th, 2010
Handler class for threaded Chat Server
*/
import java.net.*;
import java.lang.Object.*;
import java.util.*;
import java.text.*;
import javax.activation.*;
import java.io.*;
import java.util.regex.Pattern;
public class Handler implements Observer
{
//Create variables
private BufferedReader fromClient = null;
private BufferedOutputStream toClient = null;
private ChatServerSubject buffer = null;
private String myUserName = null;
private String command = null;
private boolean connectedProperly = false;
private static Pattern alphaNum = Pattern.compile("^[A-Za-z0-9\\*]+$");
//This method invoked as a separate thread
public void process(Socket client, ChatServerSubject buffer) throws IOException
{
//set up the method
this.buffer = buffer;
//try block for opening streams and getting hostname
try
{
//open Streams
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new BufferedOutputStream(client.getOutputStream());
//initial connection state
command = fromClient.readLine();
command = command.toLowerCase();
if(!command.equalsIgnoreCase("connect"))
{
error("Bad Request. Please input a proper command.", 2);
return;
}
//get username, check against userList
myUserName = fromClient.readLine();
myUserName = myUserName.toUpperCase();
if(buffer.userExists(myUserName))
{
error("Duplicate Handle. Please try another name.", 1);
return;
}
//check that username is within bounds
if(!(myUserName.length() <= 16 && alphaNum.matcher(myUserName).matches()))
{
error("Invalid handle. Handle must be an alphanumeric string with size less than or euqal to 16.", 3);
return;
}
connectedProperly = true;
//add username to userList
buffer.addUser(myUserName);
buffer.addObserver(this);
//print userList to client
printUserList();
//listen for commands
do
{
command = fromClient.readLine();
command = command.toUpperCase();
//getHandles command
if(command.equalsIgnoreCase("gethandles"))
printUserList();
//Post command
else if(command.equalsIgnoreCase("post"))
constructMessage();
//invalid command
else if(!command.equalsIgnoreCase("disconnect"))
error("Invalid request. Please input a proper command.", 2);
}
while(!command.equalsIgnoreCase("disconnect"));
}
catch(IOException ioe)
{
System.err.println(ioe);
return;
}
finally
{
//disconnection state
if(connectedProperly)
{
buffer.deleteObserver(this);
buffer.removeUser(myUserName);
}
// close streams and socket
if (fromClient != null)
fromClient.close();
if (toClient != null)
toClient.close();
if (client != null)
client.close();
}
}
//broadcast method - this method is the basic broadcasting method
//it assumes that we're sending a public message
private void broadcast(MessageObject message) throws IOException
{
System.out.println("You've reached the broadcast method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("public\n".getBytes());
toClient.write((message.getMessage() + "\n").getBytes());
toClient.flush();
}
//private message broadcast method
private void privateMessage(MessageObject message) throws IOException
{
System.out.println("privateMessage method!");
toClient.write("posted\n".getBytes());
toClient.write((message.getFromUser() + "\n").getBytes());
toClient.write("private\n".getBytes());
toClient.write((message.getMessage() + "/n").getBytes());
toClient.flush();
}
//connected/disconnected message
private void userConnected(String userName, boolean connected) throws IOException
{
if(connected)
toClient.write("connected\n".getBytes());
else
toClient.write("disconnected\n".getBytes());
toClient.write((userName + "\n").getBytes());
toClient.flush();
}
//Error message
private void error(String errorMessage, int errorNum) throws IOException
{
toClient.write("error\n".getBytes());
toClient.write((errorNum + "\n").getBytes());
toClient.write((errorMessage + "\n").getBytes());
toClient.flush();
}
//Print user list function
private void printUserList() throws IOException
{
Vector<String> currentUserList = new Vector<String>(buffer.getUserList());
toClient.write("handles\n".getBytes());
toClient.write((currentUserList.size() + "\n").getBytes());
for(int index = 0; index < currentUserList.size(); index++)
toClient.write((currentUserList.get(index) + "\n").getBytes());
toClient.flush();
}
//CreateMessage method - goes to this state after receiving the post command from the user
private void constructMessage() throws IOException
{
MessageObject newMessage = new MessageObject();
newMessage.setFromUser(myUserName);
String temp;
//read the toUser
temp = fromClient.readLine();
temp = temp.toUpperCase();
if(!(alphaNum.matcher(temp).matches() && temp.length() <= 16))
{
error("Invalid username entered. Try again!.", 3);
return;
}
if(!buffer.userExists(temp) && !temp.equalsIgnoreCase("*"))
{
error("User not found.", 4);
return;
}
newMessage.setToUser(temp);
//read the message and check to make sure it's within bounds
temp = fromClient.readLine();
if(temp.length() > 1024)
{
error("Message too Long", 5);
return;
}
newMessage.setMessage(temp);
buffer.addMessage(newMessage);
}
//update function - this is the observer functionanility implemented
//it will check the flags when the subject has changed, and act appropriately
public void update(Observable o, Object arg)
{
System.out.println("your observers are being updated!");
try
{
//check if a user was added or removed
if(buffer.userAdded())
userConnected(buffer.getNewUser(), buffer.userAdded());
else if(buffer.userRemoved())
userConnected(buffer.getDCedUser(), buffer.userAdded());
//here's the routine when we get a new message
else if(buffer.messageAdded())
{
MessageObject newMessage = buffer.getMessage();
//check if it's a private message
if(newMessage.getToUser().equals(myUserName))
privateMessage(newMessage);
//now check if it's a broadcast and not from me
else if(newMessage.getToUser().equals("*") && !newMessage.getFromUser().equals(myUserName))
broadcast(newMessage);
//now decrement and check if the counter is at 0, remove from the list if it is
newMessage.viewed();
if(newMessage.getCounter() == 0)
buffer.removeMessage(newMessage);
}
}
catch(IOException ioe)
{
System.err.println(ioe);
command = "disconnect";
return;
}
}
}
Labels:
Computer Science,
Java,
Networking
Subscribe to:
Posts (Atom)