Phobos (Server-side Scripting)

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/ajaxcodecamp






Expected duration: 120 minutes (excluding homework)



Software Needed

Before you begin, you need to install the following software on your computer. 


OS platforms you can use

Change Log


Things to be done


Lab Exercises


Exercise 0: Installation and conifguration of Phobos/jMaki plug-ins


(0.1) Install NetBeans Phobos and jMaki plug-in's to the NetBeans IDE


1. Start NetBeans IDE.
2. Select Tools from the menu-bar and select Update Center
3. Observe that the Update Center Wizard dialog box appears. Click Next.
4. Select Phobos modules. Click Next.  (Figure-0.10 below)


Figure-0.10: Phobos modules

5. Observe that two Licene Agreement dialog boxes appear.  Click Accept for both of them.
6. Observe that the modules are being downloaded. Click Next when it is finished.
7. Observe that the View Certificates and Install Module pane appear. Click Finish.
8. Observe that the Retart the IDE dialog box appears. Select Restart the IDE and click OK.
9. (Optional step) Select Tools from top-level menu and select Module Manager.
10. (Optional step) Expand AJAX and see the Phobos modules. (Figure-0.11 below)


Figure-0.11: Phobos modules


Exercise 1: Build and run "HelloWorldPhobos" Phobos application

This exercise is created from Phobos flash demo.  Before you do this exercise, you are recommended to view and listen to it.

    1. Create, build, and run "HelloWorldPhobos" Phobos application
    2. Modify "HelloWorldPhobos" Phobos application


(1.1) Create, build, and run "HelloWordPhobos" Phobos application

1. Create a Phobos NetBeans project.


Figure-1.10: Create a Phobos application project


Figure-1.11: Give a project name

2. Build and run the Project.

Figure-1.12: Display of the result


(1.2) Modify "HelloWordPhobos" Phobos application

1. Modify main.ejs as shown in Code-1.21 below.  The code fragment that needs modified is highlighted in bold and blue-colored font.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
    <head>
        <link rel="stylesheet" href=<%= library.view.quoteUrl("/jmaki-standard.css") %> type="text/css"></link>
        <title>Page Title</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <div class="outerBorder">
           
            <div class="header">
                <div class="banner"> <%= model.name %> </div>
               
                <div class="subheader">
                   
                    <div>
                        <a href="mailto:feedback@youraddress">Feedback</a> |
                        <a href="#">Site Map</a> |
                        <a href="#">Home</a>
                    </div>
                   
                </div> <!-- sub-header -->
            </div> <!-- header -->

            <div class="main">
                <div class="leftSidebar">
                   
                    Sidebar Content Here
                   
                </div> <!-- leftSidebar -->

                <div class="content" style="height:400px">
                   
                    Main Content Area
                   
                </div> <!-- content -->
       
            </div> <!-- main -->
        </div> <!-- outerborder -->
    </body>
</html>
Code-1.21: Modified main.ejs

2. Modify main.js as shown in Code-1.22 below. The code fragment that needs modified is highlighted in bold and blue-colored font.

/*
 * Main controller for the application.
 *
 * This file was generated, please edit it as needed.
 */

// define a controller module called "main"
library.common.define(controller, "main", function() {
   
    // controller class (constructor)
    function Main() {
        // insert instance initialization code here
    }
   
    // "show" action method
    Main.prototype.show = function() {
       
        /*
         Use the model global variable to pass information to the view.
         Alternatively, a view can access the controller instance by
         using the expression:
             invocation.controller
         */
        model = {name: 'My First Phobos Application'};

        // render the /application/view/main.ejs view
        library.view.render("main.ejs");
    }
       
    /*
    // This method serves all requests for actions for which there
    // is no more specific method - please uncomment and modify as needed.
    // If this method is not defined, the default behavior is to return
    // a "404 Not Found" error
    Main.prototype.onRequest = function() {
        // return a 404 error
        library.httpserver.sendNotFound();
    };
    */
   
    // export the controller class
    this.Main = Main;
});

Code-1.22: Modified main.js

3. Save the changes and refresh the browser.


Figure-1.23: Save all changes

Figure-1.24: Result


(1.3) Use jMaki component

1. Drag and drop the Accordion component under jMaki Dojo section into the section of the <div class="leftSidebar"> (line number #28) as shown below. (Figure-1.30 below)


Figure-1.30: Add a jMaki component

2. Save changes and refresh browser.

Figure-1.31: Result

3.  Modify main.ejs as shown in Code-1.34 below.  The code fragment that needs modified is highlighted in bold and blue-colored font.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
    <head>
        <link rel="stylesheet" href=<%= library.view.quoteUrl("/jmaki-standard.css") %> type="text/css"></link>
        <title>Page Title</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <div class="outerBorder">
           
            <div class="header">
                <div class="banner"> <%= model.name %> </div>
               
                <div class="subheader">
                   
                    <div>
                        <a href="mailto:feedback@youraddress">Feedback</a> |
                        <a href="#">Site Map</a> |
                        <a href="#">Home</a>
                    </div>
                   
                </div> <!-- sub-header -->
            </div> <!-- header -->

            <div class="main">
                <div class="leftSidebar">
<% library.jmaki.insert({
        component : "dojo.accordion",
        value : model.accordion
        }
        );  %>
                                
                </div> <!-- leftSidebar -->

                <div class="content" style="height:400px">
                   
                    Main Content Area
                   
                </div> <!-- content -->
       
            </div> <!-- main -->
        </div> <!-- outerborder -->
    </body>
</html>
Code-1.34: Modified main.ejs

4. Modify main.js as shown in Code-1.35 below. The code fragment that needs modified is highlighted in bold and blue-colored font.

/*
 * Main controller for the application.
 *
 * This file was generated, please edit it as needed.
 */

// define a controller module called "main"
library.common.define(controller, "main", function() {
   
    // controller class (constructor)
    function Main() {
        // insert instance initialization code here
    }
   
    // "show" action method
    Main.prototype.show = function() {
       
        /*
         Use the model global variable to pass information to the view.
         Alternatively, a view can access the controller instance by
         using the expression:
             invocation.controller
         */
        model = {name: 'My First Phobos Application',
                 accordion: {
          rows : [
                {
                    label : 'Row 0',
                    content : 'Row 0 content.'
                } ,
                {
                    label : 'Row 1',
                    content : 'Row 1 content.'
                },
                {
                    label : 'Row 2',
                    content : 'Row 2 content.'
                }  
                ]
               }};

        // render the /application/view/main.ejs view
        library.view.render("main.ejs");
    }
       
    /*
    // This method serves all requests for actions for which there
    // is no more specific method - please uncomment and modify as needed.
    // If this method is not defined, the default behavior is to return
    // a "404 Not Found" error
    Main.prototype.onRequest = function() {
        // return a 404 error
        library.httpserver.sendNotFound();
    };
    */
   
    // export the controller class
    this.Main = Main;
});
Code-1.35: Modified main.js

5. Save changes and refresh browser.
6.  Modify main.js as shown in Code-1.36 below.  The code fragment that needs modified is highlighted in bold and blue-colored font.

/*
 * Main controller for the application.
 *
 * This file was generated, please edit it as needed.
 */

// define a controller module called "main"
library.common.define(controller, "main", function() {
   
    // controller class (constructor)
    function Main() {
        // insert instance initialization code here
    }
   
    // "show" action method
    Main.prototype.show = function() {
       
        /*
         Use the model global variable to pass information to the view.
         Alternatively, a view can access the controller instance by
         using the expression:
             invocation.controller
         */
        model = {name: 'My First Phobos Application',
                 accordion: {
          rows : [
                {
                    label : 'Hello ' + java.util.Date(),
                    content : 'Row 0 content.'
                } ,
                {
                    label : 'Row 1',
                    content : 'Row 1 content.'
                },
                {
                    label : 'Row 2',
                    content : 'Row 2 content.'
                }  
                ]
               }};

        // render the /application/view/main.ejs view
        library.view.render("main.ejs");
    }
       
    /*
    // This method serves all requests for actions for which there
    // is no more specific method - please uncomment and modify as needed.
    // If this method is not defined, the default behavior is to return
    // a "404 Not Found" error
    Main.prototype.onRequest = function() {
        // return a 404 error
        library.httpserver.sendNotFound();
    };
    */
   
    // export the controller class
    this.Main = Main;
});
Code-1.36: Modified main.js

7. Save changes and refresh browser.



Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldPhobos" sample application.

                                                                                                                   return to the top


Exercise 2: Build and run sample Phobos applications

In this exercise, you are going to build and run sample Phobos applications that come with Phobos NetBeans plug-in.

(2.1) Build and run "Ajax List" sample application

1. Create a Phobos NetBeans project.


Figure-2.10: Select Ajax List sample project


Figure-2.11: Name and Location pane

2. Build and run the project

Figure-2.12: Result

(2.2) Look under the hood of the "Ajax List" sample application



1. Application Directory->script->index.js

// index script

library.httpserver.sendRedirect(library.httpserver.makeUrl("/list/show"));

2. Application Directory->controller->list.js

 /*
 * Define the list controller.
 * Essentially, library.common.define is just a package facility,
 * so here we are defining the "list" package.
 * In Phobos, there are different namespaces for controllers, libraries,
 * so we have to say that this is a controller.
 */
library.common.define(controller, "list", function() {

    /*
     * This is the list controller class. The uppercase letter
     * is a convention to show that this function is meant to be used
     * as a constructor. When a request for this controller is received,
     * the framework will call
     *     new List()
     * and the resulting instance will be the controller object that
     * will process the request.
     *
     */
    this.List = function() {
   
        /*
         * This is the method that is called whenever the "show" action
         * is requested. With the standard mapping, that happens when
         * the client tries to access the following URL:
         *     http://server:8888/list/show
         */
        this.show = function() {
       
            /*
             * The invocation.session object is created automatically
             * by the framework. You can use it to store data attached
             * to the current session. The id for the current session
             * can be found via
             *     invocation.session.id
             * It is especially useful as a database key.
             */
            var list = invocation.session.list;
            if (list == undefined) {
                /*
                 * The first time around there won't be anything in the list,
             * so we create a new one.
             * The list must be stored in the session, but Phobos only
             * allows storing Strings in session.  So, we need to
             * serialize the list into JSON.
                 */
                var list = new Array();
            invocation.session.list = library.json.serialize(list);
            }
 
            /*
             * The "model" global variable is used by convention to
             * communicate between controller and view.
             */
            model = { value: String(list)};
           
            /*
             * Finally render the view to display the calculator page.
             */
         
          library.view.render({view: "list.ejs", layout: "layout.ejs"});
       
        };

        /*
         * This is the method that performs the "compute" action.
         */
        this.compute = function() {
            /*
             * The onMethod library function is a handy way to restrict
             * the HTTP methods an action can handle.
             */
            library.httpserver.onMethod({
                /*
                 * If the method is POST, execute this function.
                 */
                POST: function() {
                    var command = String(request.getParameter("command"));
                    var entryField = String(request.getParameter("entryField"));

                    /*
                     * First, we need to deserialize the list from JSON back
               * into a list variable.  Then we can add items to and
               * remove items from the list.  Afterwards, we serialize the
               * updated list back into JSON before saving it back into session.
                     */
              var list = library.json.deserialize(invocation.session.list);
              if (command == "add") {
                var index = list.length;
                list[index] = entryField;
              }
              if (command == "remove") {
                var index = Number(request.getParameter("index"));
                var length = list.length;
                if (index != null) {
                    while (index < length - 1){
                        list[index] = list[index+1];
                        index = index + 1;
                    }
                    list.length = index;
                }
              }
                                     
                    /*
                     * Save the updated list in the session.
                     */
                    invocation.session.list = library.json.serialize(list);

                    /*
                     * Here we use write out the list to the response.
                     */

              response.setStatus(200);
              response.setContentType("text/html");
              writer = response.getWriter();
              writer.println("<ol>");
              for (var index = 0; index < list.length; ++index){
                writer.println("<li><div class=\"plain\" onmouseover=\"this.className ='over';\" onmouseout=\"this.className ='plain';\" onclick=\"removeItem('" + index + "')\">" + list[index] + "</div></li>");
             }
              writer.println("</ol>");
              writer.flush();


                },

                /*
                 * If there is no exact match for the HTTP method specified by
                 * the request, the "any" function is called.
                 */
                any: function() {
                    /*
                     * Send back a 404 error.
                     */
                    library.httpserver.sendNotFound();
                }
            });
        }
    };
});

3. Application Directory->view->list.ejs

<html>
<head> <title>list demo</title> </head>
<body>
<style>
.plain {
 color: black;
 height:25;
 font-size:18px;
 font-weight: bold;
 font-family: Arial;
 background: white;
}

.over {
 color: white;
 height:25;
 font-size:18px;
 font-weight: bold;
 font-family: Arial;
 background: blue;
 cursor: pointer;
}


.listDiv {
    position: relative;
    width: 400px;
    height: 300px;
    overflow: auto;
}

.listContainer {
    width: 400px;
    height: 350px;
}
</style>

<script type="text/javascript">

var req;
var isIE;
var list;
var entryField;

function initRequest(url) {
    var list = document.getElementById("list");
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        isIE = true;
        req = new ActiveXObject("Microsoft.XMLHTTP");
    }
    req.onreadystatechange = processRequest;
    req.open("POST", url, true);
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    req.send(null);
   
    function processRequest () {
      if (req.readyState == 4) {
        if (req.status == 200) {
          list.innerHTML = req.responseText;
        }
      }
    }

}

function submitData() {
    entryField = document.getElementById("entryField");
    var url = <%= library.view.quoteUrl("/list/compute") %> + "?command=add&entryField=" + entryField.value;
    initRequest(url);
}

function removeItem(index) {
    var url = <%= library.view.quoteUrl("/list/compute") %> + "?command=remove&index=" + index;
    initRequest(url);  
}


</script>

 <title>Shopping List using Asynchronous JavaScript and XML (AJAX)</title>
</head>
 
 <h1>Phobos Shopping List Application Using AJAX</h1>
 <hr/>
 <h2>Demo</h2>
 In the form below enter an item in the field and click the button. Watch
the item get added to the list.
 
  <div id="listForm" class="listContainer">
  <form name="autofillform" onSubmit="submitData(); return false;">
   <input id="entryField" type="text" size="20" value="Enter New Value">
   <input type="button" onclick="submitData(); return false;" value="Add to List">
  </form>
 <div id="list" class="listDiv"></div>
</div>
        <div>
        <h2>About This Demo</h2>
        <p>
        This example shows how you can do real time list operations using AJAX
        interactions in a Phobos application.
        </p>

        <h2>Contact Us</h2>
        Please send feedback or report a problem to <a href="mailto:dev@phobos.dev.java.net">dev@phobos.dev.java.net</a>
        </div>
</body>
</html>

4. Application Directory->view->layout.ejs

<html xmlns="http://www.w3.org/1999/xhtml">
    <!--
  The contents of this file are subject to the terms
  of the Common Development and Distribution License
  (the License).  You may not use this file except in
  compliance with the License.
 
  You can obtain a copy of the license at
  https://glassfish.dev.java.net/public/CDDLv1.0.html or
  glassfish/bootstrap/legal/CDDLv1.0.txt.
  See the License for the specific language governing
  permissions and limitations under the License.
 
  When distributing Covered Code, include this CDDL
  Header Notice in each file and include the License file
  at glassfish/bootstrap/legal/CDDLv1.0.txt. 
  If applicable, add the following below the CDDL Header,
  with the fields enclosed by brackets [] replaced by
  you own identifying information:
  "Portions Copyrighted [year] [name of copyright owner]"
 
  Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 -->

    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>Phobos AJAXList Demo</title>
        <link href=<%= library.view.quoteUrl("/css/main.css") %> rel="stylesheet" type="text/css" />
             
          </head>
   
    <body>
        <a name="top" id="top"></a>
        <div id="header">
            <a href="https://phobos.dev.java.net/">About Phobos</a>
        </div>
       
        <div id="content">
           
            <% library.view.layoutContent(); %>
           
        </div>
        <div id="footer">
            Built by Phobos Team at Sun Microsystems, Inc.
        </div>
    </body>
</html>



Homework Exercise (for people who are taking Sang Shin's "Ajax Programming online course")


1. The homework is to modify the  HelloWorldPhobos project as described below.   (You might want to create a new project by copying the HelloWorldPhobos project.  You can name the new project in any way you want but here I am going to call to call it as MyHelloWorldPhobos.)
2. Send the following files to ajaxhomework@sun.com with Subject as AJAXHomework-ajaxphobos.