![]() |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]()
![]() |

|
| Programming tutorials All Knowledge Info and links to posted here |
![]() |
|
Introduction to the Google Web Toolkit
|
LinkBack | Thread Tools | Display Modes |
|
|
#1 (permalink) |
|
Administrator
Posts: 18,715
Join Date: Jan 2006
Rep Power: 10
IM:
|
Published October 2006 Web 2.0 and its technical counterpart, Asynchronous JavaScript and XML (Ajax), are gaining momentum thanks to applications such as Gmail and Google Maps. For Web applications, the main benefit of Ajax is a greatly improved user experience. Although JavaScript and DHTML—the technical foundations of Ajax—have been available for years, most programmers ignored them because they were difficult to master. Today, frameworks written in JavaScript, such as Dojo, can help you build Ajax applications, but you still need a good understanding of JavaScript in order to use them. Google offers another way to help Java developers create Ajax applications more productively. This new framework, called Google Web Toolkit (GWT), can be used efficiently with Oracle JDeveloper. GWT is freely available under the Apache License v. 2.0 at http://code.google.com/webtoolkit. Main Features and Restrictions One of the main problems with Ajax development is that you need to master a large stack of heterogeneous technologies. Depending on the nature of your project (for example, business applications), this can be a great drawback. In addition, different Web browsers don’t support JavaScript and DHTML in the same way. For example, Microsoft Internet Explorer and Mozilla Firefox handle these technologies slightly differently; you’ll need to deal with this if you want your application to run seamlessly on your users’ PCs. Although most of the Ajax frameworks available today simplify development work, you still need a good grasp of the technology stack. So, if you’re planning to use Ajax to improve only your application’s user experience—if you’re not also using it as a strategic advantage for your business—it may be unwise to spend a lot of money and time on the technology. GWT proposes a different way to create Ajax applications. It uses Java as a single programming language for both the client and server sides. Is it the return of Java applets? Not at all: GWT provides a compiler that translates the Java code on the client side into JavaScript and DTHML. This solution greatly simplifies the technology stack from the programmer’s point of view: You have to master only Java. The downside is that you have less control over the client-side code of your application because it’s eventually generated by the GWT compiler. The Java code for the client side of your application is subject to restrictions because JavaScript doesn’t implement the entire object-oriented concepts and APIs available in Java. You can use only a subset of Java keywords and APIs (java.lang and java.util):
Finally, you can unit-test your code inside JDeveloper with GWTTestCase, a specialization of the class TestCase provided by JUnit. Focus on GUI Programming with GWT Ajax dramatically changes the way you develop Web applications. Most of the time, an Ajax application needs only a single Web page. Its content is modified dynamically by JavaScript and DHTML to produce a user experience similar to that provided by native applications. Therefore, GWT provides a programming model whose principles will sound familiar to Swing or AWT programmers. The GUI is no longer specified by HTML tags as in classic Web applications. It’s programmed directly with Java code in a way similar to AWT or Swing. The well-known concepts of GUI programming are available with GWT:
If the standard widgets don’t suit your needs, you can also define your own. (This topic, however, is beyond the scope of this article.) Project Structure A GWT project must comply with a pre-defined structure in order to be accepted by the compiler. Thus, it’s mandatory that you define a global package for your application. The last part of the package name must be the name of the application (such as global.package.yourApplicationName). The XML file describing your application must be found at the root of this global package. The name of this file must be the name of the application followed by the .gwt.xml extension (for example, yourApplicationName.gwt.xml). In addition, you must create three sub-packages:
Two execution modes are possible with GWT. The Hosted mode executes your application code inside an embedded server and Web browser, so you don’t have to deploy your code on an application server. It’s useful during application testing because it makes debugging simpler. The Web mode is the deployment of your Ajax Web application on a genuine application server such as OC4J. You typically use this mode when the application runs in production. Building Your First GWT Web App with Oracle JDeveloper Thus far you've learned how GWT works; now, let’s code a sample Web application (download). The sample application is a to-do list manager. Its features are quite simple: creating, editing, deleting, and prioritizing to-do lists. We chose this example because it’s easy to understand, yet its implementation covers a lot of GWT’s features. Here’s a screen shot of the final application: ![]() Step 1: Install GWT Download GWT from Google’s Web site at http://code.google.com/webtoolkit/. At the time of this writing, GWT comes in Windows and Linux versions. GWT is platform-specific because its Hosted mode works with a modified version of Firefox, which is itself platform-dependent. (We were able to use the Linux version of GWT successfully on an Apple computer, but the Hosted mode didn’t work.) GWT downloads as an archive file, which you must uncompress either with the <tt>tar -xvf</tt> command on Linux or with an unzip utility on Windows. That’s all you need to do to install the toolkit. Step 2: Run the applicationCreator Script Open a command line and go to GWT’s installation directory. This directory contains the applicationCreator script, which we’ll use to start up our application. Because we want our application to be stored in the Oracle Technology Network directory, we add “-out otn” as a parameter to the script. On Linux, type: ./applicationCreator -out otn otn.todo.client.TodoApp </pre> ![]() applicationCreator -out otn otn.todo.client.TodoApp </pre> This script generates the basic project structure, a sample “Hello word” code inside the requested application class, as well as two scripts: TodoApp-shell, which is used to run the application in Hosted mode; and TodoApp-compile, which is used to package the application for use in Web mode. Step 3: Open the Project in JDeveloper Launch JDeveloper and create a new Web project: ![]() ![]() ![]() ![]() ![]() ![]() Writing the Client-side Code The applicationCreator script above created a basic “Hello world” application, which is available in the otn.todo.client package. Here's its main method: public void onModuleLoad() { final Button button = new Button("Click me"); final Label label = new Label(); button.addClickListener(new ClickListener() { public void onClick(Widget sender) { if (label.getText().equals("")) label.setText("Hello World!"); else label.setText(""); } }); RootPanel.get("slot1").add(button); RootPanel.get("slot2").add(label); } } </pre> This method creates a button that says “Click Me”. When you click the button, the text “Hello World” is displayed. This method is divided into three parts:
Now that you’ve created the application and have seen what it generates, let’s execute it. You can easily run the project by using the TodoApp-shell script from the command line. Although this is a perfectly correct way to launch the application, you might prefer to launch it directly from within JDeveloper. To do so, click the Run menu and select Choose Active Run Configuration > Manage Run Configurations. Edit the default run configuration and use the following:
![]() ![]() ![]() Now that you’ve created a simple GWT Web application, let’s extend it using two of the most commonly used GWT features: the RPC mechanism, which allows the application to call server-side code, and the History object, which allows the user's precise handling of the browser’s Back button. Data Exchange Between Client and Server Using RPC Thus far, you’ve created only the client-side code of our application: using the GWT compiler, you’ve generated a number of HTML and JavaScript files that will run in the end-user’s browser. However, this application won’t be of much use if it can’t communicate with the server. With GWT, client/server communication is a matter of coding a servlet and making it communicate with the application. Here’s what you have to do. Create an interface that defines your service. This interface must extend Google’s com.google.gwt.user.client.rpc.RemoteService interface, and be placed into the client package (otn.todo.client, in our example). Next, code an interface that lets you read and write a to-do list on the server: package otn.todo.client; import java.util.List; import com.google.gwt.user.client.rpc.RemoteService; public interface TodoListBackupService extends RemoteService { /** * Save the to-do list on the server. */ void saveTodoList(List todoList); /** * Get the to-do list on the server. */ List getTodoList(); } </pre> Code the Servlet. On the server side, you must code a class that:
import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import otn.todo.client.Todo; import otn.todo.client.TodoListBackupService; import com.google.gwt.user.server.rpc.RemoteServiceServle t; public class TodoListBackupServiceImpl extends RemoteServiceServlet implements TodoListBackupService { private static final String TODOLIST_KEY = "TODOLIST_KEY"; public void saveTodoList(List todoList) { HttpServletRequest request = this.getThreadLocalRequest(); HttpSession session = request.getSession(); session.setAttribute(TODOLIST_KEY, todoList); } public List getTodoList() { HttpServletRequest request = this.getThreadLocalRequest(); HttpSession session = request.getSession(); if (session.getAttribute(TODOLIST_KEY) == null) { List todoList = new ArrayList(); Todo todo = new Todo("Hello from the server"); todoList.add(todo); return todoList; } else { return (List) session.getAttribute(TODOLIST_KEY); } } }</pre> This servlet stores only the to-do list in the user’s HttpSession; this, of course, is a basic way of saving data. In a normal application, you could use JNDI to access EJBs, or any of the classic patterns used to access a business service from a servlet. Finally, you must configure this servlet inside the servlet container. If you’re using the GWT shell, you can configure it inside the *.gwt.xml configuration file, which is TodoApp.gwt.xml in our example: <module> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <!-- Specify the app entry point class. --> <entry-point class='otn.todo.client.TodoApp'/> <servlet path="/todoListBackupService" class="otn.todo.server.TodoListBackupServiceImpl"/> </module></pre> If you want to configure it within another application server, such as OC4J, just add the usual XML configuration into the WEB-INF/web.xml file: <servlet> <servlet-name>TodoListBackupService</servlet-name> <servlet-class>otn.todo.server.TodoListBackupServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>TodoListBackupService</servlet-name> <url-pattern>/todoListBackupService</url-pattern> </servlet-mapping> </pre> Add some glue. The glue we need is the Async class, which must follow several rules:
import java.util.List;</pre>
TodoListBackupServiceAsync todoListBackupService = (TodoListBackupServiceAsync) GWT.create(TodoListBackupService.class); </pre> This creates at runtime a class implementing two interfaces:
ServiceDefTarget endpoint = (ServiceDefTarget) todoListBackupService; endpoint.setServiceEntryPoint("/todoListBackupService"); </pre> Now that you’ve configured this object to access the server-side service, let’s access the service. As you’ve seen in Step 3, the Async interface lets you access all the methods defined in the service, with the addition of the AsyncCallback callback parameter. This parameter is used to define the application’s behavior, depending on the success or failure of the server-side call: AsyncCallback callback = new AsyncCallback() { public void onSuccess(Object result) { printTodoList(); } public void onFailure(Throwable caught) { Window.alert("Warning : the to-do list could not be saved on the server. Maybe the server is down."); } };</pre> Let’s put it all together. Here’s the complete code of the two client-side methods accessing the TodoListBackupService business service: one for saving the to-do list on the server side, the other for reading it: /** * Update the to-do list with data from the server. */ private void updateTodoListFromServer() { TodoListBackupServiceAsync todoListBackupService = (TodoListBackupServiceAsync)GWT.create(TodoListBac kupService.class); ServiceDefTarget endpoint = (ServiceDefTarget)todoListBackupService; endpoint.setServiceEntryPoint("/todoListBackupService"); AsyncCallback callback = new AsyncCallback() { public void onSuccess(Object result) { todoList = (List)result; saveTodoListInHistory(); } public void onFailure(Throwable caught) { Todo todo = new Todo("ERROR!! Server could not be reached."); todoList.add(todo); saveTodoListInHistory(); } }; todoListBackupService.getTodoList(callback); } /** * Save the to-do list on the server. */ private void saveTodoListOnServer() { saveTodoListInHistory(); TodoListBackupServiceAsync todoListBackupService = (TodoListBackupServiceAsync)GWT.create(TodoListBac kupService.class); ServiceDefTarget endpoint = (ServiceDefTarget)todoListBackupService; endpoint.setServiceEntryPoint("/todoListBackupService"); AsyncCallback callback = new AsyncCallback() { public void onSuccess(Object result) { printTodoList(); } public void onFailure(Throwable caught) { Window.alert("Warning : the to-do list could not be saved on the server. Maybe the server is down."); } }; todoListBackupService.saveTodoList(todoList, callback); }</pre> The example application makes a server-side call at startup. This call returns the latest to-do list saved in the user’s HttpSession, or a new to-do list containing the “Hello from the server” to-do: ![]() In high-end Web applications, the browser’s Back button is too often broken. Classic Ajax applications don’t support the standard Web behavior of returning you to the previous Web page. GWT, on the other hand, allows for programmatic handling of the Back button. This is a powerful yet tricky feature that we’ll explore using our example application. The idea is to use the Back button as an Undo button: clicking it will show you the to-do list as it was before the latest event. Similarly, the Forward button will work as a Redo button. Implement the HistoryListener interface. In order to manage the Back button programmatically, the GWT application must implement the com.google.gwt.user.client.HistoryListener interface. This forces the writing of the onHistoryChanged(String _historyToken) method: public class TodoApp implements EntryPoint, HistoryListener { /** * This method is called whenever the application's history changes. */ public void onHistoryChanged(String _historyToken) { if (Integer.parseInt(_historyToken) + 1 != historyToken) { if (historyMap.get(_historyToken) != null) { historyToken = Integer.parseInt(_historyToken); todoList = (List) historyMap.get(_historyToken); } } printTodoList(); }</pre> This method is meant to receive events when the browser’s history is changed. You must add it as a listener to the GWT’s History object. This is typically done in the onModuleLoad() method, so that the History object is correctly initialized at startup: /** * This is the entry point method. */ public void onModuleLoad() { History.addHistoryListener(this); }</pre> Now, the onHistoryChanged(String _historyToken) method is called each time the browser’s history is changed. This method is able to recreate the application’s state according to a token that’s passed as a parameter. In our example, you'll use that token as a key to find a to-do list stored inside a history map. Add items to the history. In order for the onHistoryChanged(String _historyToken) method to work, you must have stored items in the history beforehand. This is easily done with the History object, using its static newItem(String historyToken) method: private void saveTodoListInHistory() { List todoListClone = new ArrayList(); Iterator it = todoList.iterator(); while (it.hasNext()) { Todo todo = (Todo) it.next(); todoListClone.add(todo.clone()); } historyMap.put(String.valueOf(historyToken), todoListClone); History.newItem(String.valueOf(historyToken)); historyToken++; }</pre> In our example, you stored the application state in a map so it can be found using the history token. Note that you used a number as the history token, but that any string could be used instead. Deploying Your Web App To deploy a Web application made with GWT, you compile the client-side code, package the result inside the .war file of your Web application, and then deploy the .war file on your favorite application server, OC4J. Compiling the Client-side Code There are several ways to compile your client-side code. When you used the applicationCreator script, GWT creates a shell script named TodoApp-compile. You can launch it from the command line. Like TodoApp-shell, it’s a fine way to compile the application; however, you may prefer to launch it directly from within JDeveloper. Another way to compile your code is to execute your application in Hosted mode so it can be done directly from JDeveloper. The toolbar of your application’s window contains a compile/browse button, like this: ![]() ![]() <path id="project.class.path"> <pathelement path="${java.class.path}/"/> <pathelement location="src"/> <pathelement path="/your/path/to/gwt-user.jar"/> <pathelement path="/your/path/to/gwt-dev-linux.jar"/> <!-- ... --> </path> </pre> Now, define a task dedicated to the compilation of your client-side code: <target name="GWTcompile"> <java classpathref="project.class.class.path" classname="com.google.gwt.dev.GWTCompiler" fork="true"> <arg value="-out"/> <arg value="${gwt.output.dir}"/> <arg value="${entry.point.class}"/> </java> </target> </pre> Set the gwt.output.dir and entry.point.class variables in a properties file, like this: gwt.output.dir=www entry.point.class=otn.todo.TodoApp </pre> Finally, declare the properties file (here, build.properties) inside your Ant script, like this: <property file="build.properties"/> </pre> You can directly launch this new target by selecting Run Target GWTCompile in the Context menu of the task: ![]()
[java] Output will be written into www\otn.todo.TodoApp [java] Compilation succeeded BUILD SUCCESSFUL </pre> Deployment in OC4J Once you have compiled the application, deploying it under OC4J is just a matter of creating a correct deployment profile. If you followed the steps described earlier, you should already have a default deployment profile. Otherwise, just select File > New... > Deployment Profiles > WAR File, and create a new profile. Using your configuration, everything should work out of the box. However, if you encounter any problems, check for the following common mistakes:
![]() As this graph shows, under normal load (a few requests per second) the server-side part of the application responds in less than 4 ms on average—an excellent result. |
|
|
|
|
|
|
![]() |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|