Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Lab 7 JavaFX TableView Purpose This lab is to create a GUI application that uses

ID: 3684440 • Letter: L

Question

Lab 7

JavaFX TableView

Purpose

This lab is to create a GUI application that uses a TableView.

Steps

Create a new empty project in Eclipse. Right-click on the src folder and select “New” -> “Package” and call it lab 7. Right-click on the new package and select “New” -> “Class”: In the New Java Class window, name your class MyGUI. Set the superclass as “javafx.application.Application”. Select the checkbox to create the main(String args[]) method. Also make sure that the “Inherit abstract methods” checkbox is selected. This will create the start(Stage primaryStage) method for you.

In the main(String [] args) method, replace the auto-generated comments with “launch(args);”.

In the start(Stage primaryStage) method, create a VBox object as the root layout. You will have to add the import statement for the VBox class. Create a scene object with the VBox as the root, and with a size of 800x600 pixels. Set the Stage’s title to “My Lab 7”, and then set the stage’s scene to be the scene you created. Create a TableView object and place it in the VBox. Create a Text object and place it as the second item in the VBox, below the TableView.

Look at the tutorial from: https://examples.javacodegeeks.com/desktop-java/javafx/tableview/javafx-tableview-example/ . It is an example of how to create a TableView to display many Book objects at the same time, with their properties arranged in columns. Your job is to take that tutorial and modify it to display HTTP_Request objects instead.

Take your HTTP_Request class from Lab 4 and change the variable types for Protocol, Address, ServerPath from String to StringProperty. You will need to import javafx.beans.property.StringProperty;.

Modify the HTTP_Request constructor so that setting the variables: protocol, address, serverPath use a SimpleStringProperty constructor, like:

protocol = new SimpleStringProperty( url.substring(0, index) );

//The substring of url from 0 to index is a string, so pass that as the initial value of the SimpleStringProperty object.

Write the get and set methods of the HTTP_Request variables so that they use the get() function to return a String, and the set(String newString) function to set the new value. For example, your code for getProtocol() would look like:

String getProtocol() { return protocol.get(); }

void setProtocol(String s) { protocol.set(s); }

Add checks for null in case some of your variables weren’t set in the constructor. If the URL doesn’t have a search path, then your searchPath variable might be null. You can’t call .get() on a null reference or you will get a NullPointerException, so check if the variables are null before calling get().

Once all of the variables and get/set methods are converted to SimpleStringProperty, you can start trying to load data in the table. Looking at the tutorial from step 4, write a getInitialTableData() function that returns an ObservableList<HTTP_Request> of objects that will show up in the table. For instance:

String addresses[] = { "https://localhost", "http://www.google.ca", "http://www.google.ca/search?q=java+TableView", "https://www.theweathernetwork.com/ca/weather/ontario/ottawa", "http://www.google.ca/search?name=value&name2=value2"};

//Type inferencing means that the compiler will take the parameter types from the variable on

// the left and use that to fill in the empty < > parameters of the constructor:

ArrayList<HTTP_Request> list = new ArrayList< >();

               for(String anAddress:addresses)

               {

                              try

                              {

                                             list.add(new HTTP_Request(anAddress, -1));

                              }

                              catch (MalformedQueryException e)

                              {

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

                              }

               }

               ObservableList<HTTP_Request> data = FXCollections.observableList(list);

Once you have created your own getInitialTableData function, you can set the ObservableList as the source of data for your table. Repeat the steps of lines 49-51 from the tutorial in your own lab 7 code.

The next step is to set up the columns of your table to display the different parts of the the HTTP_Request object. The online tutorial sets up the rows: “Title” and “Author”, but you should have “Protocol”, “Address”, “Server Path”, and “Search Parameters”. Looking at lines 53-58 in the tutorial, the pattern to create a table column is:

TableColumn myColumn = new TableColumn(“Column Title”);

myColumn.setCellValueFactory( new PropertyValueFactory(“PropertyName”) );

This example would get the value of the variable “PropertyName” and put it in the column. Since the data are HTTP_Request objects, those property names should be the variable names of the HTTP_Request class. In other words, if your variable is called MyName, then the table will call the function called “getMyName()”, and whatever that function returns will be the text placed in that row of the table.

Now create 4 columns, and pass in the correct string for the variable name to the PropertyValueFactory constructor. You will get a lot of warnings initially about using raw types, and that the function should be parameterized. We will fix those errors in the lecture on Generics.

Once you have written the code to create the TableColumns, make sure you add the columns to your table as done in line 58 of the tutorial. Change the preferred width and height of your table to something large enough to display all the columns.

Look at line 63 of the tutorial. Use that code as an example of how to set a selectionChanged eventHandler on the TableView, but for your lab, write the changed() function as a lambda function.

In the changed() function, set the text of the Text object from step 3 of this lab, the one under the TableView, as the toString() of the item that was selected (look at line 100 of the tutorial). Note that there is a bug in the tutorial code on line 94. There should be two = signs for identity comparison (==).

Once you are finished, demonstrate your work to the lab professor. Part of the demonstration should be to add another HTTP_Request object to your initial ObservableList of data, and show that it appears in the table. Also demonstrate how changing the variable name string passed into the PropertyValueFactory() constructor so that it is something other than the variable name you want to display will make your column empty the next time you run it. For example, change it to

new PropertyValueFactory(“Prrrrotocol”);

            and watch your data disappear!

HTTP-Request class:

package lab_solutions.Lab_4;

import java.util.ArrayList;

/** This class represents an HTTP Request.
*
* It should have string variables
*
*/
public class HTTP_Request {

   /** Replace the string URL, with protocol, server address, server path.*/
   protected String protocol;
   protected String address;
   protected String serverPath;
   protected int maxParams;
  
   /**Also create an ArrayList to store NameValuePair objects*/
   ArrayList<NameValuePair> params;
  
  
  
   /** Since you should no longer store the entire string. Instead rebuild the
   * URL from the various parts.
   * @return The combination of protocol,server address, server path, and search parameters
   */
   public String getURL() {
       String answer = getProtocol()+ "://" +getServerAddress();
       if(getServerPath() != null)
           answer = answer + "/" + getServerPath();
       if( params.size() > 0 )
       {
           answer += "?" + getSearchParameters();
       }
       return answer;
   }
  
  

  
   /**Constructor to call a missing constructor that sets the initial limit for the number of parameters.
   *
   * @param initial The initial search query.
   */
   public HTTP_Request(String initial) throws MalformedQueryException
   {
       this(initial, 0); //Call this constructor.
   }
  
  
   /**
   *
   * @param searchQuery The initial string.
   * @param i the limit to the number of parameters. -1 means no limit to number of parameters
   * @throws MalformedQueryException If the protocol or address are not found.
   */
   public HTTP_Request(String searchQuery, int i) throws MalformedQueryException{
       this.maxParams = i;
       int previousIndex = searchQuery.indexOf("://");
       int index;
       params = new ArrayList<>();
      
       if(previousIndex < 0)
           throw new MalformedQueryException("Protocol was not found");
       else
           this.protocol = searchQuery.substring(0, previousIndex);
      
       index = searchQuery.indexOf("/", previousIndex + 3);
       if(index > previousIndex)
       {
           this.address = searchQuery.substring(previousIndex+3, index);
           previousIndex = index;
       }
       else
           this.address = searchQuery.substring(previousIndex+3);
      
       index = searchQuery.indexOf("?", previousIndex + 1);
       if(index > previousIndex)
       {
           this.serverPath = searchQuery.substring(previousIndex, index);
           try{
               setParameters( searchQuery.substring(index + 1) );
           }
           catch(ParameterArrayFullException pa)
           {
               throw new MalformedQueryException("The parameters are not properly formed");
           }
       }
   }

   /** This algorithm parses the query string and retrieves the name value pairs.
      *
      * @param params The string containing the name value pairs
      * @throws ParameterArrayFullException
      */
   private void setParameters(String params) throws ParameterArrayFullException
   {
       int index = 0, eqIndex;
       int ampIndex = params.indexOf("&");
       String name, value;
      
       //While there are name/value pairs
       while(! (ampIndex <0 ))
       {
           //find the = between name and value
           eqIndex = params.indexOf("=", index);
          
           //get the name
           name = params.substring(index, eqIndex);
          
           //get the value
           value = params.substring(eqIndex+1, ampIndex);
          
           //add the name value pair to the array, or throw an exception
           addParameter( name, value);  
  
           //move the start index, and find the next ampersand
           index = ampIndex+1;
           ampIndex = params.indexOf("&", index);
       }
       //Now get the last parameter:
       eqIndex = params.indexOf("=", index);
       if(eqIndex >=0)
       {
           name = params.substring(index, eqIndex);
           value = params.substring(eqIndex+1);
           addParameter( name, value);  
       }
   }


   /**Returns a string that reconstructs the URL
   * @return the combination of protocol, server address, server path, and query string.
   */
   public String toString()
   {
       return getURL();
   }

   /** Returns the value of protocol
   *
   * @return the value of protocol
   */
   public String getProtocol() {
       return protocol;
   }

   /**
   *
   * @return The value of the variable address
   */
   public String getServerAddress() {
       return address;
   }

   /**
   *
   * @return The value of the variable serverPath
   */
   public String getServerPath() {
       return serverPath;
   }


   /** Rebuilds the query string based on the name value pairs in the array.
   *
   * @return A string representing the query string.
   */
   public String getSearchParameters() {
       String answer = "";
       for(int i = 0; i < params.size(); i++)
       {
           if(i > 0)
               answer += "&";
           answer = answer + params.get(i).name + "=" + params.get(i).value;
       }
       return answer;
   }

   /** Returns true if the parameter name "string" is included as a name in the array.
   *
   * @param string The name to search for
   * @return true if string is one of the names in the name/value pair array, false otherwise
   */
   public boolean includesParam(String string) {
       boolean answer = false;
       for(NameValuePair nvp : params)
       {
           if(nvp.name.equals(string))
               answer = true;
       }
       return answer;
   }

   /** Returns the value for the name that matches string
   *
   * @param string The name variable you are searching for.
   * @return The value string that is associated with string
   */
   public String getValueForParam(String string) throws ParameterNotFoundException{
       String answer = null;
       for(NameValuePair nvp : params)
       {
           if(nvp.name.equals(string))
               answer = nvp.value;
       }
       if(answer == null)
           throw new ParameterNotFoundException("Could not find " + string);
       return answer;
   }

   /** Sets the value for the name that matches string
   *
   * @param n The name variable you are searching for.
   * @param v The value you are searching for.
   * @throws ParameterNotFoundException if n is not a name in the name value pairs array.
   */  
   public void setValueForParam(String n, String v) throws ParameterNotFoundException {
       boolean found = false;
       for(NameValuePair nvp : params)
       {
           if(nvp.name.equals(n))
           {
               nvp.value = v;
               found = true;
           }
       }
       if( !found )
           throw new ParameterNotFoundException("Can't find " + n);
   }


   /** Adds the name value pair (n, v)
   *
   * @param n The string name
   * @param v The string value associated with name
   * @throws ParameterArrayFullException if the array already has the maximum size.
   */
   public void addParameter(String n, String v) throws ParameterArrayFullException{
       if( (maxParams > -1 ) && (params.size()>= maxParams))
           throw new ParameterArrayFullException( "The parameter array is full");
      
       params.add(new NameValuePair(n, v));

   }
  
   /** Create a private inner class called NameValuePair: */
   private class NameValuePair
   {
       public NameValuePair(String n, String v)
       {
           name = n;
           value = v;
       }
       public String name;
       public String value;
   }
}

Explanation / Answer

Test.java

public class Test {

   public static void main(String args[] )
   {
       String searchQuery = "https://www.google.ca/search?q=java+string&sourceid=chrome&ie=UTF-8";
       HTTP_Request request = null;
      
      
       try{
           request = new HTTP_Request(searchQuery, 4); //Create room to store 4 parameters.
       }
       catch (MalformedQueryException mqe)
       {
           System.out.println("There was an error reading the query:" + mqe.getMessage());
       }
      
       System.out.println("This should be https: " + request.getProtocol());
       System.out.println("This should be www.google.ca: " + request.getServerAddress());
       System.out.println("This should be /search: " + request.getServerPath());
       System.out.println("This should be only search parameters:" + request.getSearchParameters());
      
       System.out.println("Is the string "ie" one of the search parameters? " + request.includesParam("ie"));
       try{
           System.out.println("Value for parameter ie =" + request.getValueForParam("ie"));// Should throw ParameterNotFoundException if "ie" is not found.
           request.setValueForParam("ie", "UTF-16");
           request.addParameter("UAs", "Mozilla/5.0 (Windows NT 5.1)");
       }
       catch (ParameterNotFoundException pnfe)
       {
           System.out.println( pnfe.getMessage() );
       }
       catch(ParameterArrayFullException pafe)
       {
           System.out.println("The URL already has the maximum number of parameters. No more can be added.");
       }
      
      
      
       try{
           request = new HTTP_Request("localhost");
       }
       catch (MalformedQueryException mqe)
       {
           System.out.println("The software properly threw MalformedQueryException");
       }
      
      
      
       try{
           request = new HTTP_Request("https://localhost");
       }
       catch (MalformedQueryException mqe)
       {
           System.out.println("error reading protocol");
       }
       System.out.println("This should be https://localhost: " + request.toString());
      
      
      
       //Since the request is localhost, there should be no parameters. So trying to add
       // one should throw an exception.
       try{
           request.addParameter("UAs", "Mozilla/5.0 (Windows NT 5.1)");
       }
       catch(ParameterArrayFullException pafe)
       {
           System.out.println("The software properly threw ParameterArrayFullException");
       }
      
       try{
           request.setValueForParam("Something", "Something value");
       }
       catch (ParameterNotFoundException pnfe)
       {
           //The get message should say that "The parameter name Something was not found"
           System.out.println( pnfe.getMessage() );
       }
   }
}

MalformedQueryException.java

public class MalformedQueryException extends Exception
{
   private static final long serialVersionUID = 9173935812541082013L;
  
   private String query;
  
   public MalformedQueryException(String query)
   {
       this.query = query;
   }
  
   @Override
   public String getMessage()
   {
       return "MalformedQueryException was thrown when parsing " + query;
   }
}

ParameterArrayFullException.java

public class ParameterArrayFullException extends Exception {

   private String name;
   private String value;
   /**
   *
   */
   private static final long serialVersionUID = 5082332685647088590L;
  
   public ParameterArrayFullException(String name, String value)
   {
       this.name = name;
       this.value = value;
   }//Constructor
  
   /**
   *
   */
   @Override
   public String getMessage()
   {
       return "Array was full when trying to add a pair with the name " + name + " and value of " + value;
   }//getMessage
}

ParameterNotFoundException.java

public class ParameterNotFoundException extends Exception {
  
   private static final long serialVersionUID = -4103272627283713922L;
  
   /**
   * Stores the attempted parameter
   */
   private String param;
  
   public ParameterNotFoundException(String param)
   {
       this.param = param;
   }//Constructor
  
  
  
   @Override
   public String getMessage()
   {
       return "Parameter " + getParameter() + " was not found";
   }
  
   public String getParameter()
   {
       return param;
   }
}

HTTP_Request.java
import java.util.ArrayList;

/** This class represents an HTTP Request.
*
* It should have string variables
*
*/
public class HTTP_Request {

   /** Replace the string URL, with protocol, server address, server path.*/
   protected String protocol="";
   protected String address="";
   protected String path="";
  
   protected int maxSize;
  
  
  
   /**Also create an ArrayList to store NameValuePair objects*/
   ArrayList<NameValuePair> params;
  
  
  
   /** Since you should no longer store the entire string. Instead rebuild the
   * URL from the various parts.
   * @return The combination of protocol,server address, server path, and search parameters
   */
   public String getURL() { return toString();} //should return toString() instead
  
  

  
   /**Convert this constructor to call the HTTP_Request(initial, numParameters)
   * constructor. You should count the number of "=" characters, which should
   * be the number of parameters in the string.
   *
   * @param initial The initial search query.
   * @throws MalformedQueryException
   */
   public HTTP_Request(String initial) throws MalformedQueryException
   {
       this(initial, 0);
   }
  
   public HTTP_Request(String searchQuery, int i) throws MalformedQueryException
   {
       maxSize = i;
       params = new ArrayList<NameValuePair>();
       int temp = searchQuery.indexOf("://");
       int temp1;
       if(temp==-1)
       {
           throw new MalformedQueryException(searchQuery);
       }
       setProtocol(searchQuery.substring(0, temp));
      
      
       temp1=searchQuery.indexOf('/', temp+3);
       if(temp1==-1)
       {
           setAddress(searchQuery.substring(temp+3, searchQuery.length()));
       }
       else
       {
           setAddress(searchQuery.substring(temp+3, temp1));
           temp=searchQuery.indexOf('?', temp1);
           if(temp==-1)
           {
               setPath(searchQuery.substring(temp1, searchQuery.length()));
           }
           else
           {
               setPath(searchQuery.substring(temp1, temp));
               temp1=temp;
               int t1 = 0;
               while(temp1 > 0)
               {
                   String name;
                   String value;
                   t1 = searchQuery.indexOf('=', t1+1);
                  
                   name = searchQuery.substring(temp1+1,t1);
                   temp1 = searchQuery.indexOf('&', temp1+1);
                   if(temp1 > 0)
                   {
                       value = searchQuery.substring(t1+1, temp1);
                   }
                   else
                   {
                       value = searchQuery.substring(t1+1, searchQuery.length());
                   }
                   try
                   {
                       this.addParameter(name, value);
                   }
                   catch (ParameterArrayFullException e)
                   {
                       System.out.println(e.getMessage());
                   }
               }
           }
       }
      
   }


   public void setPath(String path)
   {
       this.path=path;
   }


   public void setAddress(String address)
   {
       this.address=address;
   }


   public void setProtocol(String protocol)
   {
       this.protocol=protocol;
   }


   /**Returns a string that reconstructs the URL
   * @return the combination of protocol, server address, server path, and query string.
   */
   public String toString()
   {
       return getProtocol()+"://"+getServerAddress()+getServerPath()+(!getSearchParameters().equals("")?"?"+getSearchParameters():"");
   }
  
   public String getProtocol()
   {
       return protocol;
   }
  
   public String getServerAddress()
   {
       return address;
   }
  
   public String getServerPath()
   {
       return path;
   }
  
   public String getSearchParameters()
   {
       String ret = "";
       for(int i = 0; i < params.size();i++)
       {
           ret += (params.get(i).toString());
           if(i < params.size()-1)
           {
               ret += "&";
           }
       }
       return ret;
   }
  
   public boolean includesParam(String name)
   {
       for(NameValuePair p:params)
       {
           if(p.getName().equals(name))
           {
               return true;
           }
       }
       return false;
   }
  
   public String getValueForParam(String value) throws ParameterNotFoundException
   {
       for(NameValuePair p:params)
       {
           if(p.getName().equals(value))
           {
               return p.getValue();
           }
       }
       throw new ParameterNotFoundException(value);
   }
  
   public void setValueForParam(String name, String value) throws ParameterNotFoundException
   {
       boolean b = false;
      
       for(int i = 0; i < params.size();i++)
       {
           if(params.get(i).getName().equals(name))
           {
               params.get(i).setValue(value);
               b = true;
           }
       }
       if(!b)
       {
           throw new ParameterNotFoundException(name);
       }
      
   }
  
   public void addParameter(String name, String value) throws ParameterArrayFullException
   {
       if(params.size() == maxSize &&maxSize != -1)
       {
           throw new ParameterArrayFullException(name, value);
       }
       params.add(new NameValuePair(name, value));
   }
  
   /** Create a private inner class called NameValuePair: */
   private class NameValuePair
   {
       private String name;
       private String value;
      
       public NameValuePair(String name, String value)
       {
           setName(name);
           setValue(value);
       }
      
       public String getName()
       {
           return name;
       }
      
       public String getValue()
       {
           return value;
       }
      
       public void setName(String name)
       {
           this.name = name;
       }
      
       public void setValue(String value)
       {
           this.value = value;
       }
      
       public String toString()
       {
           return getName()+"="+getValue();
       }
   }
}


sample output

This should be https: https                                                                                                                                 
This should be www.google.ca: www.google.ca                                                                                                                 
This should be /search: /search                                                                                                                             
This should be only search parameters:q=java+string&sourceid=chrome&ie=UTF-8                                                                                
Is the string "ie" one of the search parameters? true                                                                                                       
Value for parameter ie =UTF-8                                                                                                                               
The software properly threw MalformedQueryException                                                                                                         
This should be https://localhost: https://localhost                                                                                                         
The software properly threw ParameterArrayFullException                                                                                                     
Parameter Something was not found