In this exercise you create the plotCity web application using the NetBeans IDE 6.1.
When you complete this task, you'll have a skeleton jMaki application.
Choose File > New Project.
Under Categories, select Web.
Under Projects, select Web Application and click Next.
Type plotCity for Project Name.
Change the Project Location to any directory on your computer and click Next.
Select the GlassFish V3 TP2 Server for the server.
Keep the other settings at their default and Click Next.
Select the jMaki Ajax Framework and select the No CSS layout template.
Click Finish.
With this task, you will add the thisState and thisCity combobox widgets and the Google map widget to the page.
Open index.jsp in the editor pane if it is not already there.
Expand the jMaki Dojo node in the jMaki Palette, located on the right side of the IDE window.
Select and drag two Combobox widgets onto index.jsp
Save your changes.
You should now see the following tags on index.jsp:
<%@ taglib prefix="a" uri="http://jmaki/v1.0/jsp" %> ... <a:widget name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" /> <a:widget name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" />
Add the ID, thisState to the first Combobox widget and the ID, thisCity to the second combobox widget, so that the page now looks like the following:
<%@ taglib prefix="a" uri="http://jmaki/v1.0/jsp" %> ... <a:widget id="thisState" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" /> <a:widget id="thisCity" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" />
Add the text, Select a state: right before the first Combobox widget.
Add a paragraph tag and the text, Select a city: right before the second combobox widget.
The page should now look like this:
<%@ taglib prefix="a" uri="http://jmaki/v1.0/jsp" %> ... Select a state: <a:widget id="thisState" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" /> <p> Select a city: <a:widget id="thisCity" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" />
Expand the jMaki Google node in the jMaki Palette, located on the right side of the IDE window.
Select and drag a Google Map widget onto index.jsp, right after the Combobox widgets.
Add another paragraph tag directly before the Google map widget.
The page should now look like this:
<%@ taglib prefix="a" uri="http://jmaki/v1.0/jsp" %> ... Select a state: <a:widget id="thisState" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" /> <p> Select a city: <a:widget id="thisCity" name="dojo.combobox" value="[ {label : 'Alabama', value : 'AL'}, {label : 'California', value : 'CA'}, {label : 'New York', value : 'NY', selected : true}, {label : 'Texas', value : 'TX'} ]" /> <p> <a:widget name="google.map" args="{ centerLat : 37.4041960114344, centerLon : -122.008194923401 }" />
Save index.jsp.
(Optional) Run the application by right-clicking the project node and selecting Run.
You will see the three widgets on the page in the browser, but the combobox widgets are populated with the default set of data, and nothing happens when you select values from them. With the next task, you'll load the appropriate data into the combobox widgets.
This section details the tasks required to populate a widget with data, using the comboboxes included in the plotCity application as examples. These tasks are:
Creating the Server-Side Data
Creating the JavaBeansTM Component to Hold the Data
Accessing the Data From the Page
With this task, you are creating a properties file that contains a set of states and a set of cities for each state. This file acts as the database for the application for simplicity's sake.
Expand the plotCity node and right-click on the Source Packages node.
Select New > Java Package.
Enter plotCity as the package name.
Click Finish.
Right-click on the project in the Projects window and choose New > Other
In the New File dialog, select Other from the Categories pane.
Select Properties File from the File Types pane.
Click Next.
Enter cities in the File Name field.
Click Finish.
Select plotCity/src/java/plotCity as the location of the properties file.
Copy the following content to the cities.properties file:
AK=Anchorage,Fairbanks,Juneau,Nome AZ=Mesa,Phoenix,Scottsdale,Tucson CA=Los Angeles,Sacramento,San Diego,San Francisco OR=Bend,Eugene,Portland,Salem WA=Olympia,Seattle,Spokane,Tacoma
Save the file.
By performing this task, you are creating the bean that holds the state and city data that you can use with the comboboxes.
Expand the plotCity > Source Packages nodes.
Right-click the plotCity package and choose New > Java class.
Type StateBean for the Class Name, plotCity for the Package and click Finish.
Add the following variable declarations to the class:
private String[] states = new String [] {"Alaska", "Arizona", "California", "Oregon"}; private String[] stateCodes = new String[]{"AK", "AZ", "CA", "OR"}; protected String[] AKCities = new String[] {"Anchorage", "Fairbanks", "Juneau", "Nome"}; private ResourceBundle cityNames = null;
Add an init method after the constructor that creates a ResourceBundle object from the cities.properties file:
private void init() { cityNames = ResourceBundle.getBundle("plotCity.cities"); }
Add a call to the init method inside the StateBean constructor:
public StateBean(){ this.init(); }
Add the following getStates method to the class. It loads a JSON array with the list of state names that you initialized in step 4:
public String getStates() throws JSONException { JSONArray statesData = new JSONArray(); JSONObject stateData = new JSONObject(); for (int loop = 0; loop < states.length; loop++) { stateData.put("label", states[loop]); stateData.put("value", stateCodes[loop]); statesData.put(stateData); stateData = new JSONObject(); } return jmaki.util.JSONUtil.jsonArrayToString(statesData, new StringBuffer()); }
Add the following getCities method to the class. It loads a JSON array with the list of Alaskan city names that you initialized in step 4:
public String getCities() throws Exception { JSONObject cityData = new JSONObject(); JSONArray citiesData = new JSONArray(); for(int i = 0; i < AKCities.length; i++){ cityData.put("label", AKCities[i]).toString(); cityData.put("value", AKCities[i]).toString(); citiesData.put(cityData); cityData = new JSONObject(); } return jmaki.util.JSONUtil.jsonArrayToString(citiesData, new StringBuffer()); }
Add the following getNewCities method to the class. It loads a JSON array with the list of city names for the selected state:
public String getNewCities(String state) throws JSONException { JSONObject city = new JSONObject(); JSONArray cities = new JSONArray(); String[] names = null; try { names = cityNames.getString(state).split(","); } catch(Exception e){ return null; } for(int i = 0; i < names.length; i++){ city.put("label", names[i]); city.put("value", names[i]); cities.put(city); city = new JSONObject(); } return jmaki.util.JSONUtil.jsonArrayToString(cities, new StringBuffer()); }
Right-click the editor pane and select Fix Imports from the pop-up menu. The IDE will import the packages the class needs.
Save StateBean.java
With this task, you will initialize the combobox widgets with the server-side data.
Open index.jsp into the source editor pane.
Expand the JSP node in the Palette and select and drag Use Bean into the Source Editor below the h1 tag.
In the Insert Use Bean dialog box, enter the following values and then click OK.
ID: StateBean
Class: plotCity.StateBean
Scope: session
The IDE generates the following tag:
<jsp:useBean id="StateBean" scope="session" class="plotCity.StateBean" />
This tag gives index.jsp access to the StateBean component.
Replace the value attribute of the thisState tag with an EL expression that points to the states property of StateBean:
value="${StateBean.states}"
Replace the value element of the thisCity tag with an EL expression that points to the cities property of StateBean.
value="${StateBean.cities}"
Save the file.
(Optional) Right-click the project node and select Run.
Your browser should open and show the two comboboxes populated with the data your created. With the next set of tasks, you will add the event-handling mechanism so that you can select a city and plot it on the map.
This section details how you can use the publish/subscribe mechanism to handle events by performing the following tasks:
Publishing to a topic
Writing an Event Handler
Subscribing to a topic
After completing this task, thisState will subscribe to the /cb/getState topic.
Open index.jsp in a source editor pane.
Add a subscribe attribute to the thisState combobox and set it to the topic, /cb/getState:
<a:widget id="thisState" name="dojo.combobox" publish="/cb/getState" value="${StateBean.states}" />
Save index.jsp.
After this task is complete, the plotCity application will be able to populate the thisCity combobox widget with new data when the user selects a state from the thisState widget.
Open the glue.js file, located in plotCity/Web Pages, in the editor pane.
At the end of the glue.js file, add the following subscribe function:
jmaki.subscribe("/cb/getState/*", function(args) { var message = args.value; jmaki.doAjax({method: "POST", url: "Service?message=" + encodeURIComponent(message), callback: function(_req) { var tmp = _req.responseText; var obj = eval("(" + tmp + ")"); jmaki.publish('/cb/setValues', obj); // handle any errors } }); });
While performing the previous task, you added an Ajax call to the Service servlet to obtain the values from StateBean. You'll create the servlet with this task.
Expand the plotCity > Source Packages > plotCity node.
Right-click on the plotCity package icon and select New > Servlet.
Enter Service for the class name.
Click Finish.
Delete everything inside the servlet class so that all that the file contains are the package statement, the import statements automatically generated, and the following empty servlet class:
public class Service extends HTTPServlet{}
Add the following private variable declaration:
private ServletContext context;
Add the following init method to the class:
@Override public void init(ServletConfig config) throws ServletException { this.context = config.getServletContext(); }
Add the following doPost method to the class:
public void doPost( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { HttpSession session = request.getSession(); StateBean stateBean = (StateBean)session.getAttribute("StateBean"); String cityData = new String(); String message = request.getParameter("message"); try{ cityData = stateBean.getNewCities(message); } catch (Exception e){ System.out.println("could not get city data"); } PrintWriter writer = response.getWriter(); writer.write(cityData); session.setAttribute("stateBean", stateBean); }
This method gets the message parameter from the request, passes it to getNewCities, and passes the resulting list of cities to the response.
Save the file.
With this task, you will get thisCities to subscribe to the /cb/setValues topic so that it populates with the cities returned from StateBean.
Expand the plotCity > Web Pages nodes.
Open index.jsp in a editor pane.
Add a subscribe attribute to the thisCity widget and give it the topic /cb/setValues, as shown here:
<a:widget id="thisCity" name="dojo.combobox" subscribe="/cb" value="${StateBean.cities}" />
Save the file.
(Optional) Run the example by right-clicking the project node and selecting Run.
Now you can select a state and see the thisCity combobox populate with the names of cities located in that state. With the next task, you'll make it so the application will plot a city on the map when you select the city.
Expand the plotCity > Web Pages node.
Open index.jsp in the editor pane.
Add a publish attribute to the thisCity combobox widget and set it to /cities:
<a:widget id="thisCity" name="dojo.combobox" publish="/cities" subscribe="/cb" value="${StateBean.cities}" />
Expand the plotCity > Web Pages node.
Open glue.js in a source editor.
Add the following handler to the end of glue.js:
jmaki.subscribe("/cities/onSelect", function(item) { var city = item.value; var state = jmaki.attributes.get('thisState').getValue(); var location = city + ", " + state; var encodedLocation = encodeURIComponent("location=" + location); var url = jmaki.xhp + "?id=yahoogeocoder&urlparams=" + encodedLocation; jmaki.doAjax({url: url, callback : function(req) { if (req.responseText.length > 0) { // convert the response to an object var response = eval("(" + req.responseText + ")"); var coordinates = response.coordinates; v = {results:coordinates}; jmaki.publish("/jmaki/plotmap", coordinates); } else { jmaki.log("Failed to get coordinates for " + location ); } } }); });
Save glue.js.