Keith's Blog
Overloading Constructors. PDF Print E-mail
Written by Keith Petty   
Saturday, 14 July 2007
Today we are going to Overload the Computer.
No... wait... thats... Overload the constructor of a Computer.
Ok... I think I got it this time... were Overloading the constructor of a Class “called” Computer.
Ah yes... thats better.

Here we have a very simple class called Computer

public class Computer {
    String name;  // Brand name
    int speed;       // Processor
    int diskspace;
    int monitor;   // size
    boolean floppy;
    boolean dvd;

Now by default we get a no parameter constructor for free. And with a default no parameter constructor
we could instantiate (build) an instance of  the Computer Class in memory but it would have no value.
Oops, I meant no values set its member variables. In effect we have an empty shell of a Computer.
So instead this Class has a parameterized constructor.

    Computer(String n, int s, int d, int m, boolean f, boolean v) {
        name = n;
        speed = s;
        diskspace = d;
        monitor = m;
        floppy = f;
        dvd = v;
    }

This constructor will require that we set every member variable with a value.
A problem has popped up out on the sales floor in that all of the sales people have voted.
They all agree that it is a pain to have to indicate if the customer wants a DVD or Floppy drive.
They tell us that nobody wants a Floppy drive anymore and everyone wants a DVD.
Well, the line is drawn in the sand and we lost. We now have to alter our Computer Class so that
the sales person can skip entering values in the DVD and Floppy fields on the order form.
Now I know it might be hard to believe... but it is possible that some misguided soul will want
a computer without a DVD and with a Floppy drive.
Therefore, we will leave the original constructor as it is and write another constructor into the class.
This constructor will have the same name as the other one but will require a different set of parameters.

    Computer(String n, int s, int d, int m) {
        name = n;
        speed = s;
        diskspace = d;
        monitor = m;
        floppy = false;
        dvd = true;
    }
   
Notice we are not requiring that values be passed in for the Floppy or DVD but instead we are
setting them do a “default” value to keep the sales staff happy.
So now we have two constructors. When a constructor is called the “JVM” will choose which
one to use based on the parameter list being passed with the call.

This brings up the point that the parameter list must match exactly.
Both the type of data and the order of the data as defined in the parameter list of the constructor
make up what is referred to as the signature of the constructor.
By changing the types and or the order of the parameters we can make unique signatures thereby
allowing more than one constructor with the same name to exist with it causing a conflict or failure.

So to Overload a constructor... is to use the same name for the constructor but have a different signature (parameter list).

Next time we will cover overloading methods.
 
Memory and the Java Runtime.exec Process PDF Print E-mail
Written by Keith Petty   
Wednesday, 21 February 2007
Today, we will be learning how to get a Mac address off of your machine and that Java's memory management
does not work on external processes run by the operating system even if they were invoked by a call from
within a running Java class.

The very most important part of this exercise is found on line #111

If we do not destroy the process that we started by calling the operating system it will
remain open in memory even after we finish running our program in the JVM.

For this example we will assume that we could be dealing with
the Windows operating system
or
the Linux operating system.
 
1   import java.io.*;
2   import java.util.regex.*;
3 
4   public class MyMac {
5 
6     // main method
7     public static void main(String[] args) {
8 
9       // create an instance
10      MyMac mac1 = new MyMac();
11 
12      // call the getMacAddress() method and print the value returned
13      System.out.println(mac1.getMacAddress());
14    }
15 
16    // getMacAddress() method
17    private StringBuffer getMacAddress() {
18 
19      // StringBuffer to be used to return info about the Mac address
20      StringBuffer myMacAddress = new StringBuffer();
21 
22      // The Runtime.exec() method returns an instance of a subclass of Process
23      Process myProc = null;
24  
25      // surround with a try catch block
26      try {
27  
28        // we will be walking through each line of
29        // output produced by invoking a command line process
30        // so we will store them one at a time in this String
31        String currentLine = "";
32 
33        // the operating systems name as referenced by the System
34        String osName = System.getProperty("os.name");
35  
36        // a regular expression used to match the area of text we want
37        String macRegExp = "";
38  
39        if(osName.startsWith("Windows")) { // Windows operating system will run this
40  
41          // the regular expression we will be matching for the Mac address on Windows
42          macRegExp = "[\\da-zA-Z]{1,2}\\-[\\da-zA-Z]{1,2}\\-[\\da-zA-Z]" + 
43                      "{1,2}\\-[\\da-zA-Z]{1,2}\\-[\\da-zA-Z]{1,2}\\-[\\da-zA-Z]{1,2}";
44          // get the live Process returned through the call to the
45          // Runtime.getRuntime().exec method and invoking
46          // the Windows command ipconfig /all
47          myProc = Runtime.getRuntime().exec("ipconfig /all");
48        }
49        else if(osName.startsWith("Linux")) { // Linux operating system runs this
50  
51          // the regular expression we will be matching for the Mac address on Linux
52          macRegExp = "[\\da-zA-Z]{1,2}\\:[\\da-zA-Z]{1,2}\\:[\\da-zA-Z]" + 
53                      "{1,2}\\:[\\da-zA-Z]{1,2}\\:[\\da-zA-Z]{1,2}\\:[\\da-zA-Z]{1,2}";
54          // get the live Process returned through the call to the
55          // Runtime.getRuntime().exec method and invoking
56          // the Linux command /sbin/ifconfig -a
57          myProc = Runtime.getRuntime().exec("/sbin/ifconfig -a");
58        }
59        else{
60      // other operating systems are not supported
61          // we are done here
62          myMacAddress.append("Only works on Windows or Linux systems");
63   
64          // exiting method now
65          return myMacAddress;
66        }
67   
68        myMacAddress.append("Mac address(es)");
69   
70        // we'll wrap a buffer around the InputStream we get from the "myProc" Process
71        BufferedReader in = new BufferedReader(
72                      new InputStreamReader(myProc.getInputStream()));
73        // compile the macRegExp string into a Pattern
74        Pattern macPattern = Pattern.compile(".*" + macRegExp + ".*");
75   
76        // a Matcher object for matching the regular expression to the string
77        Matcher macMtch = null;
78   
79        while((currentLine = in.readLine()) != null) { 
80         
81          // walk through each line and try to match the pattern
82          macMtch = macPattern.matcher(currentLine);
83   
84          if(macMtch.matches()) {
85   
86            // it matched so we split the line
87            String[] splitLine = currentLine.split(macRegExp);
88   
89            for(int a = 0; a < splitLine.length; a++) {
90              // REPLACE ALL PORTIONS of the currentLine 
91              // that do not match the expression 
92              // with an empty string
93              currentLine = currentLine.replaceAll(splitLine[a].toString(), "");
94            }
95             
96            // mac address(es) returned in the StringBuffer
97            myMacAddress.append(System.getProperty("line.separator") + currentLine);
98            
99            // reset the matcher just in case we have more than one mac address 
100           macMtch.reset();
101           // after all there could more than one NIC card!
102         }
103       }
104        
105       // last but 
106       // MOST IMPORTANT !!!!!!!!!!!!
107       // we must destroy the process 
108       // or the "operating system" 
109       // won't "close the process" or
110       // clean up "it's memory allocation"
111       myProc.destroy();
112     }
113     catch(java.io.IOException e) {
114       e.printStackTrace();
115     }
116     return myMacAddress;
117   }
118 }
 
Object-oriented Programming in Java PDF Print E-mail
Written by Keith Petty   
Wednesday, 10 January 2007

I see old-fashioned procedural programming concepts being used in object-oriented languages.  I also see dead people, they're everywhere.

As a freelance programmer specializing in Java I often find myself working with legacy code that is not only poorly documented but often contains three to four times as many lines of code as is necessary to accomplish the task.

It also amazes me how often I see old-fashioned procedural programming concepts being used in spite of the fact that the programmer is writing in a true object-oriented language.

The legacy code I worked on (written in Java) from a recent contract is a good example. 

An HTTP interface was used to handle requests and responses. 

Within the requests were multiple attached data files. 

The data files were destined for a specific folder (aka mailbox1) on the server.

A Servlet (Upload1.java) was written to handle the requests to store files to mailbox1 and give a response back to the client in an XML formatted document indicating success or failure.

Later as other clients needed to have this same capability (keeping their files separated by folders) other mailboxes were added as in mailbox2, mailbox3, mailbox4 and so on.

The code to handle each one of these mailboxes was achieved by taking the original Servlet for mailbox1 (Upload1.java) and making copies for each of the other mailboxes as in Upload2.java, Upload3.java, Upload4.java and so on.

The original Upload1.java file was approximately 800 lines of code. For the most part the only difference between it and the ones to handle the other mailboxes was the information representing the path on the server for the mailbox.

I am sure that at the time these were written that seemed like quite a logical solution. 

When the decision was made to add some new functionality to the program there were a total of 27 files which needed attention.

After taking an inordinate amount of time to examine all the files and determined that the functionality of each Servlet was identical (outside of which mailbox it went to) a decision to make the code more maintainable was made. 

Before any changes could be made the following facts had to be taken into consideration.

The incoming requests from an outside client were not generated through human interaction.  These requests had been hard coded into programs residing on the outside client machines.  All changes to be made required that the incoming HTTP request would not need to be changed in any way as this would prove problematic for the outside clients.

Here are some basic concepts presented merely as examples.

  1. Rewrite Servlets for each of the individual mailboxes such as Upload1.java for mailbox1, Upload2.java for mailbox2, Upload3.java for mailbox3, Upload4.java for mailbox4 and so on.

    These Servlets however are very small and very simple.

    Their purpose is to set a new parameter into the incoming HTTP request object.

    The variable name for the parameter is simply “mailbox”.

    The value to set would be “mailbox1” or “mailbox2” or “mailbox3” or “mailbox4” based on which Servlet we are dealing with.

    Once this parameter is set the request is then forwarded to a single servlet which will handle the actual file processing for all mailboxes.

    To handle the processing for all mailboxes we rename one of the original servlets which had all the code for processing files for a given mailbox and call it "UploadProcessor.java".  We then had a request.getParameter(“mailbox”); line of code to find out which mailbox we are dealing with and then do the storing of files to their respective mailboxes and return a success or failure response in the XML document just as before.

  2. Assuming we are running on a Tomcat server, another concept is to simply write the single Servlet “UploadProcessor .java” and then edit the web.xml file and map calls for the Servlets of “Upload1”, “Upload2”, “Upload3”, “Upload4” and so on to all be handled by the  “UploadProcessor”  Servlet.

    In the UploadProcessor Servlet we simply check the requested URL for the name of the Servlet that was requested and use it to look up a value out of a properties file (which uses name value pairs).

    This concept is actually much easier to maintain if a new mailbox needs to be added.  This is because there are only two places where any editing needs to be done.  One edit would be in the web.xml file to add the name of the new “pseudo Servlet” which simply maps to our UploadProcessor Servlet and the other would be in the properties file where we would add the name of the servlet and a value for that name which represents the mailbox it should go to.

The goal in using one of these concepts was for maintainability of the code. It also demonstrates a very small step away from a deeply entrenched habit of programmers who think in procedural methodologies to write a complete new application to accommodate one simple variable.

There are other concepts which could have been used to decrease the amount of code which would need to be maintained when and if changes were needed