Thursday, June 17, 2010

Passing Thought: Applying Computer Science Theory to Economic Theory

     So I have been reading The Collected Works of F. A. Hayek Volume 1:  The Fatal Conceit - The Errors of Socialism.  Haven't quite finished the first chapter, even but it brought some interesting thoughts that I wanted to write down before I forgot them.

-- Hayek makes a reference back to Adam Smith's discussion of basic supply and demand, "the invisible hand" and all... I got to thinking, maybe one of the reasons our economy does so well at what it does (with pricing serving as an indicator that serves to automatically adjusts supply and demand to prevent overproduction and overconsumption) is essentially a form of information hiding and modularity.

I suppose I should explain those terms.  Information hiding is best explained in terms of functions and arguments.  For a programmer, when you're making use of another programmer's function, your usual concern is what the function returns and what arguments are required in what order.  If you should decide to tool around with this other programmer's code without understanding how and why he programmed it the way he did, you will almost certainly end up with a function that is less efficient - and worse, you may break the function altogether.  Thus, there is a need to prevent the first programmer from changing the second programmer's code.  I won't bore you with the variety of methods how you might go about this in an object-oriented context, but I think you get the concept.

Modularity fits along the same lines -- basically it's the concept of breaking up a program from one big "main" function into a bunch of smaller ones; each usually accomplishing a very simple, easy-to-define task.  Under these circumstances it is much easier to debug a malfunctioning program because you can usually narrow down the function that is problematic and fix it accordingly.

Now, how does this all fit in with economics?  Well in early times, and even today, the consumer rarely knows how a particular product arrived at a given store.  He usually doesn't know how it was manufactured, sometimes he doesn't even know all the contents!  My thought is this: what if this not knowing is part of why our market system works so well?  And if that is so, isn't it all the more reason command economies (such as Socialism/Fascism/Communism/Mercantilism/Absolutism/etc) rarely if ever produce positive results (nevermind trying to get results better than what the market system provides)?

Let me know in the comments what you think of the idea. -- I'll go back to reading.

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

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)   
 }
}

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
   
}
}

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;
    }
}
      

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;
        }
           
    }
}