Разработка GWT-проектов в Oracle JDeveloper

(Introduction to the Google Web Toolkit, by Stéphanie Antoine, Julien Dubois, and Jean-Philippe Retaillé)

Стефани Антуан
Жюльен Дюбуа
Жан-Филипп Ретелле

Источник: сайт публикаций по технологиям Oracle,
http://www.oracle.com/technetwork/articles/dubois-gwt-097522.html

В этой статье мы рассмотрим, как использовать Google Web Toolkit для выполнения различных задач: от базовых до достаточно сложных, таких как механизм удаленного вызова процедур (RPC), управление историей и упаковка готовых приложений.

Web 2.0 и его техническая сторона – асинхронный JavaScript и XML (Ajax) – становятся все более популярными благодаря таким приложениям, как GMail и GoogleMaps. Главным преимуществом Ajax является значительное увеличение положительных впечатлений пользователей от взаимодействия с веб-приложением. Хотя JavaScript и DHTML – техническая база Ajax – были известны и доступны для использования достаточно давно, большинство программистов игнорировали эти возможности, поскольку они были трудны для освоения. В настоящее время существуют фреймворки, написанные на JavaScript (например, Dojo), которые облегчают процесс создания Ajax-приложений. Однако при работе с ними все еще требуется хорошее понимание JavaScript.

Google пошел другим путем – и создал фреймворк GWT, позволяющий java-программистам эффективно создавать ajax-приложения без углубленного изучения JavaScript. GWT свободно распространяется под лицензией Apache License v. 2.0 и доступен для загрузки на сайте http://code.google.com/webtoolkit. Стоит отметить, что для разработки GWT-приложений идеально подходит среда Oracle JDeveloper.

Основные возможности и ограничения

Главный недостаток ajax-разработки – необходимость глубоко изучить целый список разнородных технологий. В зависимости от типа вашего проекта (например, бизнес-приложение), это может стать большой проблемой.

Кроме того, между разными браузерами существует масса несоответствий в поддержке JavaScript и DHTML. Например, браузеры Microsoft Internet Explorer и Mozilla Firefox обрабатывают эти технологии по-разному; и вам придется учитывать в коде эти особенности, если вы хотите, чтобы ваше приложение отображалось одинаково вне зависимости от выбранного пользователем браузера.

Хотя большинство из ajax-фреймворков упрощают работу программиста, вам все еще требуется хорошее понимание полного стека технологий. Поэтому, если вы планируете использовать ajax только для улучшения внешнего вида приложения – и если внешний вид не является стратегическим преимуществом на рынке – то возможно, не стоит тратить столько времени и денег на эту технологию.

GWT предлагает абсолютно новый подход к созданию ajax-приложений. Java используется как единый язык для написания и клиентской, и серверной части приложения. Возвращение Java апплетов? Нет. GWT включается в себя компилятор, который переводит Java-код клиентской части в JavaScript и DHTML. Это решение значительно упрощает технологическую сторону разработки с точки зрения программиста: вам необходимо знать только Java. Обратная сторона медали в том, что у вас меньше контроля над кодом клиентской части приложения, поскольку он в итоге генерируется GWT-компилятором.

В java -коде на стороне клиента необходимо соблюдать некоторые ограничения, поскольку в JavaScript не реализована вся объектно-ориентированная концепция и все API, доступные в Java. Вы можете использовать только некоторое подмножество API (java.lang и java.util) и ключевых слов Java:

GWT-компилятор напрямую поддерживает все простые типы данных (такие как byte, char, short, int) и соответствующие им классы (такие как Byte и Char) – за исключением типа long, который переводится в JavaScript-эквивалент типу double. Рекомендуется использовать переменные типа int вместо long.

Поддерживаются определяемые пользователем исключения, а также некоторые JVM-исключения (например, IndexOutOfBoundException). Метод Throwable.getStackTrace() недоступен (прим. пер. – доступен в hosted-режиме).

Ключевое слово synchronized не даст никакого эффекта, поскольку JavaScript выполняется в одном потоке. Монопоточное API не поддерживается.

Механизм Reflection не поддерживается. Но вы можете получить имя класса объекта, используя метод GWT.getTypeName(Object).

Не поддерживается финализация объекта в ходе сбора мусора

Некоторые контейнеры объектов из пакета java.util могут быть использованы, например, Stack, Vector и HashMap. Класс Date также доступен.

Кроме того, GWT предоставляет разработчику специальное Java API для разработки графического пользовательского интерфейса, интернационализации и разбора XML. Также предоставляется всеобъемлющая библиотека для управления взаимодействиями между клиентом и сервером. В ней используется хорошо известный механизм удаленного вызова процедур (Remote Procedure Call, RPC), реализованный в виде общего сервлета RemoteServiceServlet, который вы можете специализировать в зависимости от решаемых задач. Также вы можете использовать JavaScript Object Notation (JSON) как протокол обмена данными для ваших HTTP сообщений, отправляемых с помощью класса  GWT HTTPRequest.

GWT также предоставляет интерфейс, называемый JavaScript Native Interface (JSNI), который позволяет сочетать написанный вручную JavaScript с автогенерированным GWT-компилятором кодом. JSNI использует ключевое слово native, поддерживаемое Java Native Interface (JNI) и позволяющее объявить ваши собственные JavaScript функции. Тела этих функций размещаются внутри особым образом отформатированных комментариев.

Наконец, вы можете провести модульное тестирование вашего кода в JDeveloper с помощью GWTTestCase – специализации класса TestCase, предоставляемого JUnit.

Взгляд на программирование пользовательских интерфейсов с использованием GWT

Ajax существенно меняет способ разработки веб-приложений. В большинстве случаев ajax-приложение требует существования только одной веб-страницы. Содержимое этой страницы меняется динамически с помощью JavaScript и DHTML. Таким образом, можно получить веб-приложение, которое выглядит и ведет себя так же, как и привычные любому пользователю оконные приложения.

Крое того, GWT предоставляет модель программирования, принципы которой довольно известны Swing и AWT программистам. Пользовательский интерфейс не задается с помощью HTML-тегов, как в классических веб-приложениях. Он программируется напрямую в java-коде, в стиле, подобном стилю программирования с использованием AWT или Swing. Широко известные составляющие пользовательских интерфейсов существуют и в GWT:

Загрузка библиотеки GWT JavaScript и определение точки входа в приложение (entry point) – достаточно простой процесс: необходимо всего лишь создать простую HTML страницу.

GWT использует каскадные таблицы стилей (Cascading Style Sheets, CSS). Каждый виджет имеет свой собственный стиль, который вы можете при необходимости менять. Также вы можете создавать свои собственные CSS, которые переопределят стили по умолчанию.

Если библиотека стандартных компонентов GWT не отвечает вашим требованиям, вы можете создать свои собственные. (В данной статье эта тема освещаться не будет)

Структура GWT-проектов

GWT-проекты должны соответствовать заранее определенной структуре, чтобы компилятор мог распознать ее. Поэтому нужно обязательно определить глобальный пакет для вашего приложения. Последняя часть имени пакета должна быть именем приложения (например, global.package.yourApplicationName). XML-файл, описывающий ваше приложение, должен находиться в корне глобального пакета. Его имя должно совпадать с именем приложения и дополняться расширением .gwt.xml (например, yourApplicationName.gwt.xml). Кроме того, вы должны создать три пакета, вложенных в глобальный:

К вашему проекту должны быть подсоединены несколько jar:

Результат компиляции хранится в каталоге, имя которого совпадает с именем глобального пакета вашего приложения. Этот каталог содержит все элементы (такие как HTML-страницы, CSS, JavaScript файлы), которые составляют клиентскую часть приложения. Как обычно, все эти элементы должны быть размещены внутри вашего веб-приложения.

Ведущий (hosted) и веб- режимы

В GWT возможны два варианта выполнения. В ведущем режиме (hosted) код приложения выполняется на встроенном сервере и веб-браузере, вследствие чего отпадает необходимость развертывать код на сервере приложений. Этот режим полезен при тестировании приложений, поскольку упрощает отладку.

В отличие от hosted-режима, веб-режим предполагает развертывание вашего веб-приложения на настоящем сервере (например, OC4J). Обычно этот режим используется при размещении приложения в открытом для пользователей доступе.

Создание первого GWT-приложения с помощью Oracle JDeveloper

До сих пор мы рассматривали, как устроен и работает GWT; теперь создадим пример веб-приложения (скачать).

Разработаем приложение, которое управляет списком наших дел (ToDo list). Оно выполняет достаточно простые функции: создание, редактирование, удаление элементов списка и изменение приоритета внутри списка. Этот пример был выбран по двум причинам: во-первых, его легко понять, во-вторых, его реализация позволяет осветить много новых возможностей GWT.

Так будет выглядеть приложение после окончания разработки:

Шаг 1: Установка GWT

Загрузите GWT с сайта Google по адресу http://code.google.com/webtoolkit/. Во время написания этой статьи GWT выходил в двух версиях: для Windows и для Linux. G WT является платформозависимым, поскольку в hosted-режиме он взаимодействует со встроенным браузером, который является модифицированной версией Firefox. А Firefox, как известно, зависит от платформы. (Мы смогли использовать версию GWT для Linux на компьютере Apple, но hosted-режим не работал.)

GWT загружается архивом, который вы должны распаковать с помощью команды tar -xvf под Linux или с помощью утилиты unzip под Windows.

Шаг 2: Запуск скрипта applicationCreator

Откройте командную строку и перейдите к директории, в которой установлен GWT. Эта директория содержит скрипт applicationCreator, который обычно используется для создания основы для будущего приложения. Поскольку мы хотим, чтобы тестовое приложение хранилось в директории Oracle Technology Network, мы добавляем “-out otn” параметр к скрипту. В ОС Linux вызов скрипта будет выглядеть так:

./applicationCreator -out otn otn.todo.client.TodoApp

В Windows используйте следующую команду:

applicationCreator -out otn otn.todo.client.TodoApp

Этот скрипт создает базовую структуру проекта, код примера "Hello World" внутри созданных классов приложения, а также два скрипта: TodoApp-shell, который используется для вызова приложения в hosted-режиме; и TodoApp-compile, используемый для упаковки приложения перед использованием в веб-режиме.

Шаг 3: Открытие проекта в JDeveloper

Вызовите JDeveloper и создайте новый веб-проект:

Нажмите Next.

JDeveloper спросит, где разместить новый проект. Введите имя вашего приложения в поле Project Name , и выберите корневую директорию проекта (определенную в Шаге 2) как Directory Name:

Нажмите Next, и далее определите тип вашего проекта как приложение J2EE 1.4:

Нажмите на кнопку Next.

Выберите свойства вашего веб-проекта: Document Root - директория www текущего проекта, а в качестве J2EE Web Application Name и J2EE Context Root выберите имя проекта:

Это позволит создать JDeveloper проект, но при попытке его запуска будут возникать ошибки компиляции, поскольку библиотеки GWT не включены в classpath проекта. Зайдите в свойства проекта, выберите в дереве настроек узел "Libraries" и добавьте библиотеку gwt-user.jar:

Теперь ваш проект компилируется, и структура проекта выглядит примерно так:

Написание кода клиентской части

Скрипт applicationCreator создал базовое "Hello World" приложение, которое располодено в пакете otn.todo.client.

Ниже показан сгенерированный главный метод:

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);
  }
}

Этот метод создает кнопку с текстом "Click Me". При нажатии на кнопку отображается текст "Hello World".

Этот метод можно разделить на три части:

  1. Создание компонентов Button и Label
  2. Создание объекта ClickListener. Причем код очень похож на тот, который вы бы написали в Swing; поэтому GWT проще освоить, если вы уже писали оконные приложения на Java
  3. Отображение компонентов на HTML странице: slot1 и slot2 - HTML-элементы страницы.

HTML-страницы используется как основа, "скелет" приложения, и располагается в директории src/otn/todo/public. На ней определены как ячейки таблицы два HTML-элемента (slot1 и slot2).

Выполнение и отладка в hosted-режиме

После создания приложения и обзора его основ, давайте его запустим.

Вы можете легко запускать проект, вызывая из командной строки скрипт TodoApp-shell. И хотя это наиболее корректный путь запуска приложения, возможно вы предпочтете вызов напрямую из JDeveloper. Для этого зайдите в пункт меню Run и выберите Choose Active Run Configuration > Manage Run Configurations. Отредактируйте конфигурацию вызова по умолчанию, используя следующие параметры:

Ваша конфигурация должна выглядеть в итоге подобно этой:

Для запуска вашего приложения следует добавить еще две библиотеки к classpath приложения: специфичный для платформы GWT jar и директорию с исходниками src приложения:

Теперь вы можете запустить приложение из JDeveloper.

Настройки были достаточно сложными, но, к счастью, вы можете использовать их снова и снова при последующих запусках или при отладке приложения. Для отладки просто используйте кнопку Debug вместо Run. Отладчик используется как обычно: можно устанавливать точки останова, пошагово исполнять код, и т.д.:

Особенно впечатляет то, что вы можете производить отладку клиентского кода, написанного на Java, с помощью стандартного отладчика JDeveloper.

Расширяем GWT Web App: от простого к сложному

Теперь, когда вы создали простое веб-приложение, можно расширить его с помощью двух наиболее часто используемых возможностей GWT: механизма RPC, который позволяет клиентской части приложения вызывать код сервера, и объекта History, который позволяет адекватно обрабатывать нажатие кнопки "Назад" в браузере.

Обмен данными между клиентом и сервером с помощью RPC

До сих пор мы рассматривали создание кода клиентской части: используя GWT-компилятор, генерировали некоторое количество HTML и JavaScript-файлов, которые будут выполняться в браузерах конечных пользователей. Однако приложение не имеет особого смысла, если оно не взаимодействует с сервером.

В GWT клиент/серверные взаимодействия реализуются путем создания сервлетов. И это то, чем мы займемся.

Создайте интерфейс, который определяет необходимый вам ервис.

Этот интерфейс должен быть расширением стандартного интерфейса com.google.gwt.user.client.rpc.RemoteService, и размещаться в пакете клиента (otn.todo.client, в нашем примере).

Далее, объявите в интерфейсе, что он позволяет читать и писать список дел на сервер:

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();
}

Пишем сервлет.

В серверной части вы должны создать класс, который:

  1. Расширяет стандартный класс Goggle: com.google.gwt.user.server.rpc.RemoteServiceServlet (который, в свою очередь, расширяет класс Java: javax.servlet.http.HttpServlet - что делает его эффективным сервлетом)
  2. Реализует интерфейс, написанный на шаге 1
  3. Находится в серверном пакете (otn.todo.server, в нашем случае)
package otn.todo.server;

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;x

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

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);
               }
        }
}

Этот сервлет сохраняет список дел в пользовательской сессии (HttpSession); конечно, это является самым простым способом сохранения данных. Но в нормальных приложениях вы можете использовать JNDI для доступа к EJB, либо любые другие классические модели доступа к бизнес-логике приложения из сервлета.

Наконец, перейдем к настройке этого сервлета внутри контейнера сервлетов. Если вы используете оболочку GWT, вы можете настроить его в файле конфигураций  *.gwt.xml (называется TodoApp.gwt.xml в нашем примере):

<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>

 

Если вы хотите настроить его для другого сервера приложений, например для OC4J, просто добавьте обычную xml-конфигурацию в файл WEB-INF/web.xml:

<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>

Просто добавь воды.

Для полной гармонии во взаимодействии клиента и сервера сейчас не хватает только асинхронных методов. Добавим класс Async, для которого должны выполняться следующие правила:

  1. Он расположен в клиентском пакете (otn.todo.client)
  2. Он имеет такое же имя, что и интерфейс, описанный в шаге 1, но с добавлением в конце постфикса Async
  3. Он содержит те же методы, что и интерфейс, описанный в шаге 1, но у каждого метода добавляется дополнительный параметр: com.google.gwt.user.client.rpc.AsyncCallback callback.
package otn.todo.client; 
import java.util.List;

import com.google.gwt.user.client.rpc.AsyncCallback; 

public interface TodoListBackupServiceAsync { 
 /** 
 * Save the to-do list on the server. 
 */ 
 void saveTodoList(List todoList, AsyncCallback callback); 
 
 /** 
 * Get the to-do list on the server. 
 */ 
 void getTodoList(AsyncCallback callback); 
}

Использование внутри приложения.

Для получения доступа к серверному коду из клиентской части приложения, используйте класс com.google.gwt.core.client.GWT, который позволяет воздать особый объект:

TodoListBackupServiceAsync todoListBackupService =
               (TodoListBackupServiceAsync) GWT.create(TodoListBackupService.class);

Эти строки создают во время выполнения класс, реализующий два интерфейса:

Второй интерфейс используется для конфигурирования класса, и может указывать на сервлет, определенный в шаге 2:

ServiceDefTarget endpoint = (ServiceDefTarget) todoListBackupService; 
               endpoint.setServiceEntryPoint("/todoListBackupService");

Теперь, когда вы настроили доступ к сервисам клиентской части, можно попытаться получит доступ к сервису. Как вы заметили на шаге 3, асинхронный интерфейс позволяет получить доступ ко всем методам, определенным в сервисе, и содержит дополнительный параметр обратной связи: AsyncCallback callback. Этот параметр используется для того, чтобы определить, как будет вести себя приложение при успешной или ошбочной попытке доступа к сервису:

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 (один метод для сохранения списка дел, второй для чтения):

/** 
     * Update the to-do list with data from the server. 
     */ 
    private void updateTodoListFromServer() { 
        TodoListBackupServiceAsync todoListBackupService = 
            (TodoListBackupServiceAsync)GWT.create(TodoListBackupService.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(TodoListBackupService.class); 
        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); 
    }

Тестовое приложение обращается к серверу при запуске. Этот вызов возвращает список дел, сохраненных в пользовательской сессии, либо новый список, содержащий один элемент “Hello from the server”:

Управление кнопкой "Назад"

В Ajax веб-приложениях логика работы кнопки "Назад" в браузерах часто нарушается. Классические ajax-приложения не поддерживают Web-стандарт поведения, позволяющий пользователю вернуться на предыдущую страницу.

GWT, с другой стороны, дает возможность программной обработки кнопки "Назад". Это мощная, но сложная функциональность, которую мы рассмотрим, используя наше тестовое приложение. Идея заключается в использовании кнопки "Назад" как кнопки Undo (Отменить): по щелчку на ней вы увидите действия, которые были перед самым последним. Кроме того, кнопка "Вперед" будет работать как кнопка Redo (Повторить).

Реализуем интерфейс HistoryListener.

Для программного управления кнопкой Back, GWT приложение должно реализовывать интерфейс com.google.gwt.user.client.HistoryListener. Также должен быть реализован onHistoryChanged(String _historyToken) метод:

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(); 
    }

Этот метод предназначен для получения событий при изменении истории браузера. Вы должны добавить его в качестве слушателя к объекту History. Обычно это делают в методе onModuleLoad(), чтобы объект History корректно инициализировался при старте приложения:

/** 
  * This is the entry point method. 
  */ 
    public void onModuleLoad() { 
 
        History.addHistoryListener(this); 
         
    }

Теперь метод onHistoryChanged(String _historyToken) вызывается каждый раз при изменении истории браузера.

Этот метод может пересоздавать состояние приложения согласно токену (знаку, флагу), передаваемому как параметр. В нашем примере токен используется как ключ, по которому можно найти список, хранимый внутри истории (history map).

Добавление элементов в историю.

Чтобы заставить метод onHistoryChanged(String _historyToken) корректно работать, необходимо заранее сохранять элементы в историю.

Это просто сделать для объекта History, используя его статический метод newItem(StringhistoryToken):

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++; 
    }

В этом примере вы храните состояние приложения в истории (history map), и оно может быть найдено по ключу. Заметим, что в качестве ключа могут быть использованы не только целые числа, но и любая строка.

Развертывание веб-приложения

Для развертывания вашего GWT-приложения, необходимо откомпилировать код клиента, запаковать результат в .war файл вашего веб-приложения, и затем загрузить этот .war на любой сервер приложений (например, OC4J).

Компиляция клиентского кода

Есть несколько способов скомпилировать код клиента. Когда вы вызывали скрипт applicationCreator, GWT создал shell-скрипт под названием TodoApp-compile. Вы можете вызвать его из командной строки. Это хороший способ скомпилировать приложение, однако разработчики часто предпочитают вызывать его напрямую из среды JDeveloper.

Другой способ скомпилировать код - это выполнить ваше приложение в hosted-режиме в JDeveloper. на панели инструментов вашего приложения найдите кнопку "compile/browse", подобную этой:

В конце процесса компиляции ваше приложение откроется в окне браузера, используемого по умолчанию. Также в окне  GWT development shell будет отображено, что компиляция прошла успешно:

Независимо от того, как вы компилировали код, вы увидите сгенерированные файлы в папке www/otn.todo.TodoApp вашего проекта.

Последним способом компиляции кода является использование Ant. GWT не предоставляет какие-либо специальные задачи Ant, но вы можете вызвать любой класс Java (например, GWTCompiler) со стандартной задачей Java Ant. Во-первых, необходимо определить путь до включаемых GWT jars:

 <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>

Затем определим задачу, выполняющую компиляцию кода клиента:

<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>

Установим в файле конфигураций переменные gwt.output.dir и entry.point.class, например, так:

gwt.output.dir=www 
entry.point.class=otn.todo.TodoApp

И наконец, укажем файл конфигураций (build.properties) в самом Ant-скрипте:

<property file="build.properties"/>

Вы можете напрямую вызывать эту новую цель, выбрав Run Target GWTCompile в меню Context задачи:

В окне Apache Ant Log отобразятся следующие результаты:

GWTcompile: 
 [java] Output will be written into www\otn.todo.TodoApp 
 [java] Compilation succeeded 
 
BUILD SUCCESSFUL

Развертывание в OC4J

После компиляции приложения, развертывание его под OC4J включает в себя всего лишь создание правильного профиля развертывания. Если вы последовательно выполняли все шаги, описанные ранее, то сейчас у вас уже есть профиль развертывания, созданный по умолчанию. В противном случае выберите в меню File > New... > Deployment Profiles > WAR File и создайте новый профиль.

При использовании такой конфигурации, все должно работать по умолчанию. Однако, если у вас возникнут какие-либо проблемы, проверьте, не совершили ли вы следующие распространенные ошибки:

Развернутое приложение состоит из двух частей:

С точки зрения производительности просмотр пользователем статических ресурсов очень эффективен (так как не требует обращения на сервер); единственным "узким местом" приложения может быть взаимодействие клиента и сервера. Но благодаря OC4J разработчики имеют доступ к некоторым интересным графикам анализа производительности сервера:

Как показывает этот график, при нормальной нагрузке (несколько запросов в секунду) на сервер, отклик приходит менее чем через 4мс в среднем. Это великолепный результат.

Как показывает этот график, при нормальной нагрузке (несколько запросов в секунду) на сервер, отклик приходит менее чем через 4мс в среднем. Это великолепный результат.

Stéphanie Antoine – ведущий разработчик J2EE, работает во Франции, в крупной фирме-консультанте программного обеспечения. Julien Dubois и Jean-Philippe Retaillé – являются J2EE экспертами и соавторами; их книга, Spring par la Pratique (Eyrolles, 2006) – первая книга во Франции про фреймворк Spring J2EE