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

Lab 4 Inner classes and Exceptions Purpose This lab is to declare an inner class

ID: 3671925 • Letter: L

Question

Lab 4

Inner classes and Exceptions

Purpose

This lab is to declare an inner class and use exceptions. This lab is a continuation of Lab 1, using the URL class. The UML class for the updated URL class is given, with new methods and variables. I am also giving you the public static void main method that tests your implementation of the new methods. However, the steps given show you how to use Eclipse’s suggested solutions to help speed up the development of new code.

Background

Look at the initial URL: "https://www.google.ca/search?q=java+string&sourceid=chrome&ie=UTF-8".

There are several pieces of information encoded in this string. First, the protocol is the string that comes before “://”. In the above string, the protocol is “https”, but many web pages use “http” instead.

After the protocol is the server address. It comes between the “://” string and the next “/” character. In the example, the server address is www.google.ca.

The server path is the directory on the server where the document is located. It might not be part of the string so you have to handle that case. If it is there, then it comes after the server address, and the “/” character. In the example, the path is “search”.

The search parameters, if they exist, come after the “?” character, and are separated by “&” characters. For example, “?param1=value1&param2=value2&param3=value3”, has parameters: “param1=value1”, “param2=value2”, “param3=value3”.

Parameters and values are separated by the “=” character. For our original example: the parameters q has the value “java+string”, the parameter sourceid has the value “chrome”, and the parameter ie has the value “UTF8”.

We will learn how to use some useful methods in the String class: indexOf(String), substring(int start, int end) to help separate the parts of a query string and set the appropriate portions of the HTTP_Request object.

Steps

Pull the latest source code from Github in the CST8284_W16 project. There should be a Lab_4 package. Create a new Eclipse project for Lab4, and copy and paste the Lab_4 package into your new project. DO NOT do your lab work in the CST8284_W16 project because pulling code from Github afterwards will overwrite your work.

Look in the Lab_4 package, there are sample HTTP_Request and Test classes. If you look at the main method in the Test.java class, there are a lot of red underlines indicating error in the code. For example, line 10 has new HTTP_Request(searchQuery, 4); underlined. It is because the constructor for HTTP_Request with a string and int parameter doesn’t exist. If you put your mouse over the red line, a pop-up window should appear saying “The constructor HTTP_Request(String, int) is undefined. There is another section of the pop-up window that suggests 5 possible quick fixes: 2 are to remove parameters from the constructor, 2 are to change existing constructors to have the right number of parameters. The last suggestion is to create a new constructor with String, int parameters. The String should be the URL, and the int should be the maximum number of parameters that you can store in your HTTP_Request object. An int of -1 should mean that there is no limit. Click your mouse on the last suggestion to create a new constructor. Both constructors should throw MalformedQueryExceptions if the protocol or address are not found.

Put your mouse over the MalformedQueryException error and look at the pop-up.

The correct error is that the class doesn’t exist so select the quick fix that creates the class. Notice that because the MalformedQueryException is in a catch() block, Eclipse can guess that it should be a subclass of Exception. Click Finish to create the class.

The next errors: request.getProtocol(), request.getServerAddress(), request.getServerPath(), request.getSearchParameters(), request.includesParam() are caused because these methods don’t exist yet in your HTTP_Request class. Select the quick fix to create the method in HTTP_Request. Do the same for getValueForParam(), setValueForParameter(), and addParameter().

Click the quick fix to create the ParameterNotFoundException class and add the getParameter() method, and then create the ParameterArrayFullException class.

In your HTTP_Request class, create a private inner class called NameValuePair that has both a name and value String variables.

Go to the new constructor that you created and write an algorithm that will scan through the query string to find the individual parts. First, find the protocol type. Use the indexOf(“://”) method to calculate where in the request string the “://” string begins. It should be 5 because “https” comes first, followed by “://”. The indexOf() method returns -1 if the string wasn’t found. In that case, the constructor should throw an exception because the string “://” must appear in the URL. Look at the main method to tell which exception should be thrown, and give an appropriate message saying why the exception was thrown, in this case ‘The protocol could not be determined’.

Once you have found the protocol, the next portion should be the server address. It comes between the “://” and the next “/” characters. There is a version of indexOf() that looks for a string starting at a given position: indexOf(String str, int fromIndex). Since you should have found where the “://” starts, you should look for the indexOf(“/”) starting from the previous position.

www.google.ca/search?q=java+string&sourceid=chrome&ie=UTF-8.

If there is no “/”, then indexOf(“/”) will be -1, and all of the other values: server path and query parameters should be set to null. Otherwise, the server path is the substring from the first “/” until the end of the string, or the first “?” if there is one.

?q=java+string&sourceid=chrome&ie=UTF-8

The ? represents a query, and everything that comes after are parameters separated by &, where ParameterName=Value.

q=java+string&sourceid=chrome&ie=UTF-8

Write an algorithm that separates each of these parts of the search query, and sets the server name, server path, and query string name/value variables of the HTTP_Request object.

The name/value variables should be stored in order in an ArrayList<NameValuePair>. The addParameter(String name, String value) method should add a new NameValuePair object to the ArrayList. If the ArrayList size is equal to the maxSize, then it should throw a ParameterArrayFullException, with an appropriate message.

The setValueForParam(String name, String value) should iterate through the ArrayList and look for a name that matches, and overwrite the current string with the new string value. If the parameter name doesn’t exist, then it should throw a ParameterNotFoundException with the message explaining which parameter name was being set.

Once this runs properly without crashing, set a breakpoint on line 7 in Test.java and demonstrate the flow of the program to the lab professor. This lab is worth 16 marks:

Line 12 HTTP_Request constructor does not throw MalformedQueryException     +1

MalformedQueryException class exists         +1

lines 19-22 return correct values       +4

line 24 includes parameter works properly               +1

lines 26-28 pass without throwing exception            +3

lines 30&34 classes exist for ParameterNotFoundExeption and ParameterArrayFullException +2

line 46 exception is thrown properly +1

Line 52 does not throw MalformedQueryException             +1

line 65 throws an exception               +1

line 73 throws an exception               +1

Here is the code that was given and must be used:

package Lab_4;


/** 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 URL;
  
  
  
   /**Also create an ArrayList to store NameValuePair objects*/
  
  
  
  
   /** 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 URL; } //should return toString() instead
  
  

  
   /**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)
   {
       this(initial, 0); //Create this constructor. -1 means no limit to number of parameters
   }
  
  


   /**Returns a string that reconstructs the URL
   * @return the combination of protocol, server address, server path, and query string.
   */
   public String toString()
   {
       return ""; //Change what gets returned.
   }
  
  
  
   /** Create a private inner class called NameValuePair: */
}

package Lab_4;

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"));
           request.setValueForParam("ie", "UTF-16"); // Should throw ParameterNotFoundException if "ie" is not found.
           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() );
       }
      
   }
}

Explanation / Answer

package Lab_4; /** * Created by Majeed on 2/26/2016. */ import java.util.ArrayList; /** This class represents an HTTP Request. * * It should have string variables * */ public class HTTP_Request { protected String protocol; protected String serverAddress; protected String serverPath; protected String searchParameters; protected int maxSize; /**Also create an ArrayList to store NameValuePair objects*/ protected ArrayList queryParameters; public HTTP_Request(String initial, int limitParams) throws MalformedQueryException { maxSize = limitParams; queryParameters = new ArrayList(); int index = initial.indexOf("://"); if (index == -1 || index != 5) throw new MalformedQueryException("The protocol could not be determined"); protocol = initial.substring(0, 5); index = initial.indexOf("/", 8); if (index == -1) { serverPath = null; serverAddress = initial.substring(8, initial.length()); } else { int questionMarkIndex = initial.indexOf("?", index); if (questionMarkIndex == -1) questionMarkIndex = initial.length(); else { searchParameters = initial.substring(questionMarkIndex + 1); String[] searchTokens = searchParameters.split("&"); for (String searchToken: searchTokens) { String[] nameValue = searchToken.split("="); queryParameters.add(new NameValuePair(nameValue[0], nameValue[1])); } } serverPath = initial.substring(index, questionMarkIndex); } } /**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, -1); //Create this constructor. -1 means no limit to number of parameters } /**Returns a string that reconstructs the URL * @return the combination of protocol, server address, server path, and query string. */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(protocol).append("://").append(serverAddress); if (serverPath != null) sb.append(serverPath); if (searchParameters != null) sb.append("?").append(searchParameters); return sb.toString(); } public String getProtocol() { return protocol; } public String getServerAddress() { return serverAddress; } public String getServerPath() { return serverPath; } public String getSearchParameters() { return searchParameters; } public String includesParam(String name) { for (NameValuePair pair: queryParameters) { if (pair.getName().equals(name)) { return Boolean.toString(true); } } return Boolean.toString(false); } public String getValueForParam(String name) throws ParameterNotFoundException { for (NameValuePair pair: queryParameters) { if (pair.getName().equals(name)) { return pair.getValue(); } } throw new ParameterNotFoundException("Parameter: " + name + " being searched for not found"); } public void setValueForParam(String name, String value) throws ParameterNotFoundException { boolean isAvailable = false; for (NameValuePair pair: queryParameters) { if (pair.getName().equals(name)) { pair.setValue(value); isAvailable = true; break; } } if (!isAvailable) throw new ParameterNotFoundException("Parameter: "" + name + "" could not be found"); } public void addParameter(String name, String value) throws ParameterArrayFullException { if (queryParameters.size() == maxSize) throw new ParameterArrayFullException("Parameters Limit Reached: Number of parameters allowed " + maxSize); queryParameters.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) { this.name = name; this.value = value; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } }