Skip to main content
Engineering LibreTexts

15.7: Java Servlets and Server Pages

  • Page ID
    59292
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    In this chapter we have been discussing the client/server model of computing. Thus far we have learned how to implement client/server applications using socket connections between programs running on different computers. Because it requires the programmer to directly create and manage the socket protocol, this socket-level approach is a low-level approach. It is important to know about sockets and how they are used, but most client/server applications are programmed at a much higher level by using Java library classes.

    Our focus in this section will be to give you a brief sense of how Java programs can be integrated into the Web pages. We will discuss two approaches: Java Server Pages (JSP) and Java servlets. As Web-based approaches, both of these require the use of HTML (HyperText Markup Language) code, the language that is used for coding Web pages. This means that in order to write your own servlets and JSPs you would really have to learn a little about HTML code. Fortunately, learning HTML code is not difficult and although it doesn’t fit within the scope of this book, you can easily find books or Web sites that cover basic HTML coding. Moreover, in order for servlets and JSPs to work, they must be associated with a Web server that is specially configured to understand Java code. At the end of this section we will provide links to a Web site where you can learn more about HTML and about how to set up your own JSPs and servlets.

    Java Server Pages

    A Java Server Page (JSP) is a Web page that contains small snippets of Java code. The simple example discussed here was downloaded from on online tutorial at

     http://developer.apple.com/internet/java/tomcat1.html

    The Java code on a JSP embedded within brackets and interspersed among a page’s HTML tags. The Java code can extend over one or more lines. Figure [fig-jspcode] shows the complete sourcecode for a simple JSP.

    <html><head><title>Very Simple JSP Example</title></head>
    <body bgcolor="white">
    
    <h1>Very Basic JSP</h1>
    
    Current time: <%= new java.util.Date() %>
    <br><br>
    
    Reload this page to watch the greeting change.
    <br><br><b>
    
    <!-- including lines of Java code in an HTML page -->
    <%
       int um = (int)( Math.random() * 5 );
       switch ( um )
       {
          case 0: out.println("Welcome"); break;
          case 1: out.println("Bienvenidos"); break;
          case 2: out.println("Bienvenue"); break;
          case 3: out.println("Bienvenuti"); break;
          case 4: out.println("Willkommen"); break;
          default: out.println("Huh? " + um);
       }
       out.println("<br>");
    %>
    </b>
    </body>
    </html>

    In this example we see two uses of Java code. In the first case, a JSP expression tag is used to display the current date on the Web page:

      Current time: <%= new java.util.Date() %>

    A JSP expression element begins with . The expression contained within the tag is evaluated, converted into a Java String and inserted into the Web page. In this case the Date object is evaluated and its string value is displayed on the Web page (Fig. [fig-jspscreen]).

    In the second case, a scriptlet of Java code uses the Math.random() method to display a random greeting on the Web page. A scriptlet extends over several lines and is contained within the tag (Fig. [fig-jspcode]). Note the use of the output statement, out.println(). The out object is a built-in output stream. Anything written to out will be transmitted as part of the HTML code that is sent to the Web page. In this case, one of the greetings is displayed each time the page is reloaded.

    Obviously, this simple example only scratches the surface of what you can do with JSP. If you want to learn more about JSP, there are many helpful online tutorials available, such as http://www.jsptut.com/. However, remember that in order to experiment with JSP, it will be necessary to have access to a JSP-aware Web server either on your own computer or on one provided by your service provider.

    Java Servlets

    A Java servlet is another high-level approach to developing client/server applications. A servlet is a Java program that runs on a Web server and processes Web pages using the HyperText Transfer Protocol (HTTP). In a Web application, the browser serves as the client.

    Many URLs that we access on the web are pure HTML files that are simply transmitted back to the browser by the Web server. For example, the URL for a simple HTML document on the author’s Web site is:

    http://www.cs.trincoll.edu/~ram/jjj/hello.html

    If you type that URL into a Web browser, the Web server at www.cs.trincoll.edu would transmit the following text file to your browser, which would then render and display the document.

    <HTML>
    <HEAD>  
       <TITLE>Very Simple HTML Document</TITLE>
    </HEAD>
    
    <BODY>
        <CENTER><H1>Hello</H1></CENTER>
    </BODY>
    </HTML>

    If we want the server to do some processing and submit the results of that processing to the browser, we could use a Java servlet. A servlet can perform some processing task and return the results of that task to the browser in the form of an HTML document.

    The difference between a Java servlet and a Java applet is that an applet performs all of its processing on the client side of the client/server connection. A servlet performs its processing on the server side. When you load a Java applet into a browser, the Web server downloads the applet’s bytecode into the browser. The browser then runs the byte code, assuming, of course, it is equipped with a plugin for the Java Virtual Machine (JVM). When you access a Java servlet from a browser, the Web server performs some computation and transmits just the results to the browser.

    There are several advantages of servlets over applets. First, servlets cut down significantly on the amount of data that has to be transmitted to the browser. Second, because the servlet returns an HTML-encoded page, there are many fewer platform-related problems. All browsers can interpret HTML code, but not all browsers have the right plugins for interpreting Java applets. Third, servlets are not subject to the same security and privacy restrictions as Java applets, which, as we saw earlier in the chapter, must be run as untrusted code. Finally, Java servlets can directly access large databases and other resources that are stored on the server. Access to such resources via an applet would be very difficult and inefficient.

    So, servlets have many advantages over applets. Because of these advantages they have quickly become an industry standard for developing client/server applications on the Web.

    A Simple Servlet Example

    To illustrate the difference between a Java servlet and a simple HTML page, Figure [fig-hiservlet] shows a servlet that creates a Web page that says “Hello.” As you can see, a servlet is a Java program. In addition to libraries that you are already familiar with, such as java.io, it also imports names from two new libraries: javax.servlet and javax.servlet.http. The program defines a single class, the HelloServlet class, which is a subclass of HttpServlet, the standard superclass for all Java servlets.

    import java.io.*;
    import java.text.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class HelloServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
            throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
    
            out.println("<HTML>");
            out.println("<HEAD>");
            out.println("<TITLE>Simple Servlet</TITLE>");
            out.println("</HEAD>");
            out.println("<BODY>");
            out.println("<H1> Hi, from a Java Servlet.</H1>");
            out.println("</BODY>");
            out.println("</HTML>");
        }
    }

    The servlet defines the doGet() method. This is a method that is defined in the HttpServlet superclass. Our HelloServlet is overriding that method. In general, Web browsers make two types of requests when they request a Web page, a get or a post. We won’t go into the differences between these requests. The result in either case is that the Web server will respond to the request by transmitting some text data to the browser. When a browser makes a get request, the server will automatically call the servlet’s doGet() method. That’s why we have to override it. The HttpServlet class also has a default doPost() method, which is called automatically to handle post requests.

    Note the two parameters in the doGet() method: the HttpServletRequest and the HttpServletResponse. The doPost() method has the same two parameters. These are the objects that are used to hold the data that are communicated between the client and the server. When the client (browser) makes a get request, the HttpServletRequest objects hold the data contained in the request. These data might include data that a user has typed into an HTML form. We will see an example of how to extract these data in the next section.

    The HttpServletResponse object is where the servlet will write its response. As you can see from examining the code, the HttpServletResponse object has an associated output stream, a PrintWriter, and it is a simple matter to write text to that output stream. Note that the text we write is HTML code that is practically identical to the code contained in the previous HTML example.

    The Nim Servlet

    The simple servlet in the preceding section illustrates how the servlet communicates with the client—by writing HTML code to the HttpServletResponse object. Let’s now look at an example that uses two-way communication between the client and server. To keep the example simple, we will revisit once again on our One Row Nim game. In this application the servlet will manage the One Row Nim game and will play against a human player, who will access the game through a Web browser.

    The browser interface for this version of the game is shown in Figure [fig-nimscreen]. As you can see, it is a simple Web page. The sticks in this instance are replaced by pennies. In addition to reporting the total number of pennies left, the page displays images of pennies. This Web page itself is organized as a simple HTML form, which contains one text field for the user’s input. Each time the user hits the RETURN key in the text field, the user’s input is transmitted to the servlet where it is processed. The servlet then transmits a new page to the user’s browser, which shows the updated state of the game.

    Let’s now look at the servlet program itself, whose code is shown in Figures [fig-nimservlet] and [fig-nimservlet2]. This servlet program is quite a bit longer than the simple hello server, but it is not really any more complex or difficult. The NimServlet extends the HttpServlet superclass and overrides the doGet() method. Note that it also overrides the doPost() method, by simply having that method call the doPost() method. So this servlet will work for both get and post requests.

    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class NimServlet extends HttpServlet {
        
        private OneRowNim nim = null;
        private NimPlayer nimPlayer = null;
    
        public void doPost(HttpServletRequest request, 
                           HttpServletResponse response)
          throws IOException, ServletException
        {
            doGet(request, response);
        }
    
        //  The doGet() method goes here.
    
    } // NimServlet

    -11pc

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
    {
      response.setContentType("text/html");
      PrintWriter out = response.getWriter();
      HttpSession session = request.getSession(true);
    
      out.println("<html>");
      out.println("<body>");
      out.println("<head>");
      out.println("<title>Simple Nim Game</title>");
      out.println("</head>");
      out.println("<body>");
    
      out.println("<center><h1>One Row Nim</h1></center>");
      out.println("<center><h1>The Rules</h1>");
      out.println("A random number of pennies is thrown on the table.<BR>");
      out.println("Two players alternate making moves,<BR>");
      out.println("picking up between 1 and 3 pennies on each move.<BR>");
      out.println("The player who picks up the last penny loses.<BR><BR>");
    
      if (nim == null) {
        nim = new OneRowNim(7 + (int)(Math.random() * 11));
        nimPlayer = new NimPlayer(nim);
        out.println("<h2>You go first!</h2></center>");
      } else {
        int userTakes = Integer.parseInt(request.getParameter("pickup"));
        if (!nim.takeSticks(userTakes)) {
           out.println("<h2><font color='red'>Woops. That's an illegal move!. Try again. </font><h2>");
        } else if (!nim.gameOver()) {
           nim.changePlayer();
           out.println("<h2>So, you took <font color='blue'>" + userTakes + "</font><BR>"); 
           out.println("That leaves me with <font color='blue'>" + nim.getSticks() + "</font><BR>");
           int iTake = nimPlayer.move();
           out.println("OK. I take <font color='red'>" + iTake + " </font>pennies.<BR></h2>");
           nim.takeSticks(iTake);
           nim.changePlayer();
        } // if not gameover
      } // else nim != null
      if (!nim.gameOver()) {
        if (nim.getPlayer() == 1)
          out.println("<center><h1>Who's Turn: <font color='magenta'> Your turn </font><h1></center>");
        else
          out.println("<center><h1>Who's Turn: <font color='magenta'> My turn </font><h1></center>");
        out.println("<center><h1>Pennies Left: <font color='red'>" + nim.getSticks() + "</font><h1></center>");
        out.println("<center>");
        for (int k=0; k < nim.getSticks(); k++)
          out.println("<img src='http://xroads.virginia.edu/~CAP/LINCOLN/cent.jpg' width='25' height='25'>");
        out.println("</center><br>");
    
        out.println("<center>");
        out.println("<form action='/jjj3e/NimServlet' method='POST'>");
        out.println("<table border='0'>");
        out.println("<tr><td>How many do you pickup?: </td>" +
            "<td><input type='text' name='pickup' value='0'></td></tr>");
        out.println("</table>");
        out.println("</center>");
        out.println("</form>");
      } else {
        out.println("<h1><font color='red'>Game over!</font><h1>");
        if (nim.getPlayer() == 1)
          out.println("<center><h2>And the winner is : <font color='magenta'> Me.</font><h2></center>");
        else
          out.println("<center><h2>And the winner is: <font color='magenta'> You.</font><h2></center>");
        out.println("<center><h2><font color='magenta'> Nice game!</font><h2></center>");
        out.println("<center><h2>To play again, just reload the page.<h2></center>");
        nim = null;
      } // else game over
      out.println("</body>");
      out.println("</html>");
    }// doGet

    NimServlet uses two other objects: a OneRowNim object and a NimPlayer object. You should be familiar with these from Chapter 8, so we won’t go over their internal details here. The OneRowNim object manages the playing of the game and the NimPlayer object acts as a computer-based player of the game. Note that variable references for these two objects are declared in the beginning of the class definition, but the objects themselves are declared within the doGet() method.

    One of the tricky parts of NimServlet is how we declare the OneRowNim object. As you might already know, the HTTP protocol is said to be a stateless protocol, which means that each time a browser submits a request to a Web server, the Web server sees the request as a completely independent communication. The server does not, in and of itself, maintain an internal state that keeps track of a series of transactions with a particular browser session. For example, when you are shopping for books on Amazon, each time you go to a new page, the Amazon web server treats that request as a completely independent action. Web applications use various techniques to get around the stateless nature of the HTTP protocol. One technique is to use cookies to record the progress of a session. A cookie is a small text file containing data that the server uses to keep track of a user’s session. Data that identifies the user and the state of the transaction—for example, buying a book—are passed back and forth between the browser and the server each time the user visits the Amazon Web site.

    Java’s servlet library contains methods and objects that support the use of cookies. But rather than use cookies, we will use the OneRowNim object itself to keep track of the state of the Nim game. The first time the user submits a request to Nim servlet—that is, when the user first visits the servlet’s URL—the servlet will create an instance of the OneRowNim object. Creating a OneRowNim object will have the effect of initializing the game, including the creation of a NimPlayer to play the server’s moves. The OneRowNim object will persist throughout the playing of the game and will handle all subsequent user’s move. When the game is over, the NimServlet will, in effect, dispose of the OneRowNim object by setting its reference to null. Thus, in outline form, the code for creating and disposing of the OneRowNim object goes as follows:

    // First request: Start a new Nim game
    if (nim == null) { 
       nim = new OneRowNim(7 + (int)(Math.random() * 11));
       nimPlayer = new NimPlayer(nim);
    // Code deleted here.
    else {
       // Code for playing the game goes here.
    }
    if (!nim.gameOver()) {
      // Code for playing the game goes here.
    } else {
       // Code deleted here.
      nim = null;
    }

    Those places where code has been deleted in this segment would contain Java code for responding to the user’s input and deciding how many pennies to take.

    Unlike the HelloServlet, the NimServlet accepts input from the client. The code for handling user input is as follows:

    int userTakes = 
            Integer.parseInt(request.getParameter("pickup"));

    This statements reads the user’s input from the text field on the Web page by using the request.getParameter() method. This is one of the public methods of the HttpServletRequest object. The name of the text field is ’pickup’, which is provided as an argument in this method call. As we noted above, the text field itself is on element of the HTML form contained in the servlet’s Web page. The HTML code for creating the form element is also generated by the servlet:

    -3pc

    out.println("<form action='/jjj3e/NimServlet' method='POST'>");
    out.println("<table border='0'>");
    out.println("<tr><td>How many do you pick up?: </td>" +
      "<td><input type='text' name='pickup' value='0'></td></tr>");

    Unless you already know something about HTML, you won’t completely understand this code. We will give a minimal explanation. In HTML, a text field is known as a input element of type ’text’. Note that this code segment names the element ’pickup’, which allows our program to refer to it by that name.

    The remaining details in the servlet have to do with managing the game and repeat concepts that were covered in Chapter 8. We won’t repeat them here, other than to note that any output sent to the client must be in the form of HTML statements, hence the appearance throughout the code of HTML tags, which are the elements in the angle brackets.

    Setting Up and Using Java Servlets

    Java servlets can only run on a Web server that is specially configured to interpret them. To experiment with the servlets discussed in this chapter, just go to the following URL:

    http://www.cs.trincoll.edu/~ram/jjj/servlets

    That web page contains links to both the HelloServlet and NimServlet. It also contains links to Web sites where you can learn more about creating servlets. In order to create and run your own servlets, you will need access to a Web server that has been specially configured to run servlets. There are several very good free servers that support Java servlets. You can download one of these onto your own computer and follow the directions on how to set it up. Links to Java servlet sites are also provided on our servlets page.

    busy waiting

    callback method

    client

    client/server protocols

    domain name

    ethernet protocol

    File Transfer Protocol (FTP)

    get

    HyperText Transfer Protocol (HTTP)

    internet

    Internet

    Internetworking Protocol (IP)

    Java Server Page (JSP)

    packet

    port

    post

    protocol

    router

    sandbox security model

    scriptlet

    server

    servlet

    Simple Mail Transfer Protocol (SMTP)

    socket

    trusted code

    Uniform Resource Locator (URL)

    World Wide Web (WWW)

    An internet is a collection of two or more distinct networks joined by routers, which have the task of translating one network’s language to the other’s. The Internet is a network of networks that uses the Internet Protocol (IP) as the translation medium.

    A protocol is a set of rules that controls the transfer of information between two computers in a network. The HyperText Transfer Protocol (HTTP) governs information exchange on the World Wide Web (WWW). The Simple Mail Transfer Protocol controls mail service on the Internet. The File Transfer Protocol (FTP) controls the transfer of files between Internet computers. The Domain Name System (DNS) governs the use of names on the Internet.

    A client/server application is one that divides its task between a client, which requests service, and a server, which provides service. Many Internet applications and protocols are based on the client/server model.

    Lower-level protocols, such as the ethernet protocol and token ring protocol, govern the transmission of data between computers on a single network. The Internet Protocol (IP) translates between such protocols.

    A Uniform Resource Locator (URL) is a standard way of specifying addresses on the Internet. It consists of several parts separated by slashes and colons: method://host:port/path/file. The java.net.URL class is used to represent URLs.

    Files of text or data (images, audio files) on the Internet or Web can be downloaded using the same InputStreams and OutputStreams as files located on a disk. To read or write a resource located on a network, you need to connect its URL to an input or output stream.

    The java.awt.Toolkit class contains useful methods for downloading Images into an application.

    A socket is a two-way communication channel between two running programs on a network. The java.net.Socket class can be used to set up communication channels for client/server applications. The server process listens at a socket for requests from a client. The client process requests service from a server listening at a particular socket. Once a connection exists between client and server, input and output streams are used to read and write data over the socket.

    The fully connected mesh topology requires the most cables.

    The fully connected mesh topology would have the most potential to use alternate routes if one of the host computers crashed.

    The star topology would be rendered completely useless if its central hub crashed.

    Prentice Hall’s Web server is located at

    http://www.prenhall.com 

    The protocol is http. The host computer is named www. Prentice Hall’s domain name is prenhall, and it is part of the com (commercial) Internet domain.

    For buying a piece of software at a bookstore, the server would be the sales clerk. The protocol would be to select the software from off the shelf, bring it to the checkout counter, give the sales clerk money, and get a receipt.

    For buying a piece of software over the phone, the server would be the telephone sales clerk. The protocol would be to select from a catalog, provide the sales clerk with your credit card information, and say goodbye.

    For buying a piece of software over the Internet, the server would be the computer that handles the transaction. The protocol would be to select the item from a Web-based form, provide the form with personal and payment information, and click on the Buy button.

    To play sounds along with slides in the SlideShowFrame, you would make the following modifications to the code:

    private Clip soundClip[] = new Clip[NIMGS];
    private Clip currentClip = null;

    Declare an array of URLs to store the URLs of the audio files you want to play.

    Assign Clips to the array at the same time you input the images:

    for (int k=0; k < NIMGS; k++) {
      url = 
       new URL( "http://www.cs.trincoll.edu/~ram/jjj/slide" + 
                                                  k + ".gif");
      slide[k] = imageIO.read( url );
      URL soundURL = 
       new URL("http://www.cs.trincoll.edu/~ram/jjj/sound" +
                                                   k + ".au");
      AudioInputStream audio =
            AudioSystem.getAudioInputStream(url); 
      DataLine.Info info = new DataLine.Info(Clip.class, 
                               audio.getFormat()); 
      soundClip[k] = (Clip) AudioSystem.getLine(info);
    }

    Change the nextSlide() code to the following

    public void nextSlide() {
        currentClip.stop(); // stop sound playback
        currentClip = soundClip[nextImg]; // get next soundClip
        currentClip.setFramePosition(0); // start clip at beginning
        currentImage = slide[nextImg]; 
        nextImg = ( nextImg + 1) % NIMGS; 
        repaint ();
    }

    Each time an image is displayed in paint(), play the corresponding sound by using the URL from the array:

    public void paint(Graphics g) {
        if (currentImage != null) {
            g.drawImage(currentImage,10,10,this);
            currentClip.start();
        }
    }

    The scramble service would be implemented by defining two new classes: The ScrambleServer class is a subclass of Server, and the ScrambleClient class is a subclass of Client. The ScrambleClient would implement the requestService() method and the ScrambleServer would implement the provideService() method.

    If you specify the wrong host name or port, you will get the following exception: java.net.ConnectException: Connection refused.

    If you leave off the \n in the writeToSocket() call, nothing will go wrong because the writeToSocket() method will catch this error and add the end-of-line character to the string before sending it to the server. The server reads lines from the client, so every communication must end with \n or the protocol will break down.

    Explain the difference between each of the following pairs of terms:

    2

    Stream and socket.

    Internet and internet.

    Domain name and port.

    Client and server.

    Ethernet and Internet.

    URL and domain name.

    What is a protocol? Give one or two examples of protocols that are used on the Internet.

    What service is managed by the HTTP protocol?

    Give examples of client applications that use the HTTP

    Why is it important that applets be limited in terms of their network and file system access? Describe the various networking restrictions that apply to Java applets.

    What does the Internet Protocol do? Describe how it would be used to join an ethernet and a token ring network.

    Describe one or two circumstances under which a ConnectException would be thrown.

    Modify the SlideShowFrame so that it plays an audio file along with each slide.

    Design and implement a Java applet that downloads a random substitution cryptogram and provides an interface that helps the user try to solve the cryptogram. The interface should enable the user to substitute an arbitrary letter for the letters in the cryptogram. The cryptogram files should be stored in the same directory as the applet itself.

    Design and implement a Java application that displays a random message (or a random joke) each time the user clicks a GetMessage button. The messages should be stored in a set of files in the same directory as the applet itself. Each time the button is clicked, the applet should download one of the message files.

    Write a client/server application of the message or joke service described in the previous exercise. Your implementation should extend the Server and Client classes.

    Write an implementation of the scramble service. Given a word, the scramble service will return a string containing all possible permutations of the letter combinations in the word. For example, given “man,” the scramble service will return “amn, anm, man, mna, nam, nma.” Use the Server and Client classes in your design. (See the Self-Study Exercises for a description of the design.)

    Challenge: Modify the Nim server game in this chapter so that the client and server can negotiate the rules of the game, including how many sticks, how many pick ups per turn, and who goes first.


    This page titled 15.7: Java Servlets and Server Pages is shared under a CC BY 4.0 license and was authored, remixed, and/or curated by Ralph Morelli & Ralph Wade via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.