Интеграция XForms и Google Web Toolkit: Часть 1. Представляем JSNI - Java Script Native Interface (исходники)

Майкл Галпин

Введение

Инструментарий Google Web Toolkit (GWT) приобрел широкую популярность как средство разработки приложений Ajax. GWT позволяет Java разработчикам быстро создавать Ajax приложения на Java, не требуя от них никаких знаний JavaScript. XForms, в свою очередь, является дальнейшим развитием стандарта HTML и позволяет разрабатывать сложные динамические компоненты на основе простых конструкций. Поскольку обе технологии предоставляют мощные средства для решения многих задач, то почему бы не использовать их вместе? Это и стало главной темой нашей серии.

Читая статьи нашей серии, вы разработаете простое Web-приложение для обработки данных о звездах рока и их альбомах. Приложение будет использовать GWT и XForms, а под конец вы сможете комбинировать их произвольным образом. В первой части мы начнем с простых примеров, демонстрирующих использование технологий, например, c приложения KitchenSink, прилагаемого в качестве примера к GWT. Этот пример будет использован для демонстрации разнообразия компонентов пользовательского интерфейса, содержащихся в GWT.

Предварительные требования

В данной статье используется GWT версии 1.4 и подключаемый модуль Mozilla XForms версии 0.8 (см. Ресурсы). Модуль Mozilla XForms работает с любым браузером на основе Mozilla, например, Firefox или Seamonkey. Использование GWT предполагает определенные знания Java, а так же Web-технологий, таких как HTML и CSS. Кроме этого, в статье широко используется JavaScript. Наконец, технология XForms разработана в соответствии с парадигмой MVC (Model-View-Control), так что желательно знакомство с MVC. В то же время опыт использования GWT или XForms хотя и полезен, но необязателен.

XForms

Создавая Web-приложения в наши дни, скорее всего, вы создаете именно Ajax-приложения. Вы, вероятно, в курсе множества стандартных вариантов использования Ajax, таких как асинхронное добавление или изменение данных. Однако вы наверняка удивитесь, узнав, что многие подобные возможности были известны задолго до появления термина "Ajax". Многие стандартные вещи, реализуемые с помощью Ajax, могут быть выполнены с использованием XForms.

XForms - это основанная на стандартах технология, которая обещает стать центром спецификации HTML следующего поколения. Главной идеей XForms является отделение данных от их физического представления. Звучит знакомо, не правда ли? Отделив данные от представления, их можно просматривать любым способом, основанным на HTML. Данные также можно привязать к элементам форм для удобства их добавления и модификации.

Ajax используется для решения многих подобных задач. В Ajax данные тоже отделены от представления в HTML. При этом зачастую дело заканчивается созданием объектов JavaScript для хранения данных на странице HTML. XForms предлагает более стандартный подход к данной проблеме - хранение экземпляров данных в XML (см. пример ниже).

Хранение данных в XML

В XForms используется знакомый подход Model-View-Controller (модель-представление-контроллер, MVC), в соответствии с которым данные формы (XForm) хранятся в модели (XForm-model). Пример модели приведен в листинге 1.

Листинг 1. Пример модели XForms

                        <xf:model id="my-model" xmlns="http://www.w3.org/1999/xhtml" 
		xmlns:xf="http://www.w3.org/2002/xforms">
            <xf:instance id="my-data" src="my-data.xml" xmlns=""/>
            <xf:bind calculate="sum(../Item/Amount)" nodeset="/Data/Total"/>
            <xf:submission action="my-data.xml" id="update-from-local-file" 
			instance="my-data" method="get" replace="instance"/>
            <xf:submission action="my-data.xml" id="view-xml-instance" 
                 method="get"/>
            <xf:submission action="my-data.xml" id="saveToServer" 
                 method="put"/>
        </xf:model>

Здесь необходимо выделить несколько важных моментов. Во-первых, обратите внимание на элементы XForm-instance - именно в них хранятся данные модели. Существует возможность задания источника данных аналогично ссылкам на ресурсы в JavaScript и CSS. Если задан атрибут src, браузер загрузит соответствующий объект отдельным HTTP запросом. Объект данных также может быть представлен непосредственно внутри элемента XForm-instance. Также отметим, что и сама модель, и объекты имеют идентификаторы (ID). Это необходимо для доступа к ним с помощью других средств и технологий, как будет показано ниже.

Наконец, взгляните на различные объявления XForm-submission. Действия, описываемые с их помощью, похожи на действия (actions), присутствующие в обычных формах HTML, т.е. ссылки на обработчики данных форм. Обратите внимание на атрибут method: он выполняет ту же функцию, что и в формах HTML - а именно задает способ отправки HTTP-запроса. Все вышеперечисленное является частью модели. Теперь посмотрим на уровень представления в XForms.

Представления в XForms

Описав модель, вы легко можете создавать представления содержащихся в ней данных. XForms предоставляет множество стандартных элементов для манипуляции данными модели. Каждый элемент может обращаться к экземплярам данных, а благодаря тому, что описание модели задано в XML, мы можем свободно перемещаться по данным и ссылаться на них, используя выражения XPath. XForms полностью поддерживает спецификацию XPath 2.0. Рассмотрим на несколько примеров.

В простейшем случае модель может быть просто отображена в браузере с помощью элемента output, как показано в листинге 2.

Листинг 2. Использование элемента output

                
<xhtml:div id="sum">
  <xf:output class="item-amount" ref="/Data/Total" 
  xmlns="http://www.w3.org/1999/xhtml">
  </xf:output>
</xhtml:div>

Атрибут ref - это ни что иное, как выражение XPath, вычисляемое применительно к данным модели. Обратите внимание, что вы можете смешивать выражения XHTML, такие как div или атрибут class в CSS, с элементами XForms. И это вовсе не хитрый маневр, а просто напоминание, что XForms является неотъемлемой частью будущего HTML.

XForms был разработан для использования в интерактивных приложениях, а не только для отображения данных. Поэтому, разумеется, существуют компоненты для редактирования данных (см. листинг 3).

Листинг 3. Элементы управления в формах

                
<xf:input class="item-amount" ref="Amount" xmlns="http://www.w3.org/1999/xhtml">
    <xf:label>Amount</xf:label>
</xf:input>
<xf:submit submission="saveToServer" xmlns="http://www.w3.org/1999/xhtml">
    <xf:label>Save</xf:label>
</xf:submit>

В листинге 3 показан простой пример создания поля ввода с меткой и кнопкой отправки. Все компоненты в этом примере привязаны к модели, например, поле ввода привязано к экземпляру данных. С точки зрения элементов HTML, поле ввода будет заполнено соответствующим значением из модели при загрузке страницы.

Компонент submit, как и следовало ожидать, превращается в знакомую HTML-кнопку "submit". Он тоже привязан к модели, а именно - к элементу "submission". Этот элемент описывает действия формы, т.е., из компонента "submit" будет создана кнопка HTML типа "submit", нажатие на которую вызовет HTTP-запрос типа "post" по адресу, указанному в элементе "submission" модели. Что же именно будет отправлено? Разумеется, данные формы в XML. Благодаря привязке данных к полю ввода пользователь может ввести новое значение в поле, и именно оно будет автоматически сохранено в модель перед отправкой HTTP-запроса на сервер.

Возможно, вы ассоциируете отправку данных HTML-формы с навигацией по адресу, указанному в атрибуте action формы. Это было типично для "Web 1.0", но, к счастью, не для XForms. С точки зрения приложения, использующего XForms, отправка формы - это просто отправка данных на сервер и ничего больше. Этот подход является логическим продолжением четкого разграничения между моделью, а именно, данными и операциями над данными, такими как отправка на сервер, и представлением.

Но вернемся к реальности. Все это выглядит весьма типично для приложений Ajax, не так ли? Однако в Ajax нам скорее всего потребовалось бы несчетное количество строк кода на JavaScript, который привязывал бы данные к форме, перехватывал нажатие на кнопку отправки, отправлял асинхронный запрос на сервер, и, наконец, отрисовывал фрагмент представления, отображающий необходимые данные. У нас все эти действия выполняются внутри XForms. Внутри XForms можно реализовать очень многое, но при этом XForms не является некой замкнутой технологией, потенциально ограничивающей свободу пользователя. Она предоставляет эффективные средства взаимодействия с такими фундаментальными клиентскими технологиями, как HTML DOM и JavaScript.

XForms и JavaScript

В XForms-приложении данные могут храниться в модели с привязкой к различным представлениям. Этот подход, повсеместно использующийся в серверных приложениях, становится все более популярен на клиентской стороне, во многом благодаря Ajax. А поскольку XForms - это технология построения клиентских приложений, то логично, что она поддерживает доступ к данным с помощью родного для браузеров языка JavaScript.

Все возможности XForms полностью открыты для вызовов через JavaScript, исполняющегося внутри той же страницы, т.к. все элементы XForms, относящиеся как к модели, так и к представлению, являются частями документа HTML DOM. Все это неотъемлемая часть следующего поколения HTML, так что вы можете легко обращаться к элементам XForms так же, как, например, к элементу div в стандартном HTML, т.е. используя знакомый метод getElementById(). Пример обращения к модели XForms с помощью JavaScript представлен в листинге 4.

Листинг 4. Доступ к модели XForms на JavaScript

                
var model = document.getElementById("my-model");
var instance = model.getInstanceDocument("my-data");
var dataElement = instance.getElementsByTagName("Data")[0];
var itemElements = dataElement.getElementsByTagName("Item");
var cnt = itemElements.length;
var descripElement = itemElements[0].getElementsByTagName("Description")[0];
descripElement.childNodes[0].nodeValue = "";
var amtElement = itemElements[0].getElementsByTagName("Amount")[0];
amtElement.childNodes[0].nodeValue = "0";
model.rebuild();
model.recalculate();
model.refresh();

Как видно из листинга 4, к модели XForms можно обращаться точно так же, как и к любой части DOM. Вначале вы получаете некий JavaScript-объект первого уровня. Обратите внимание, что он предоставляет специализированные методы, такие как getInstanceDocument(). Этот метод предоставляет доступ к XML-данным модели. Данные модели - это полноценный XML-документ, так что вы можете читать и модифицировать его содержимое стандартными методами, как и любой другой XML-документ.

GWT

Инструментарий GWT был впервые представлен на конференции JavaOne в 2006 г. и вскоре приобрел широкую популярность среди Java-разработчиков. Этот инструментарий позволяет разработчикам быстро создавать Web-приложения на основе Ajax, в основном используя только свой опыт в Java и лишь базовые знания HTML и CSS. Это удобно не только для быстрого создания прототипов, но и для промышленных разработок. К примеру, Mashup Editor - онлайн-среда от Google для разработки Web-приложений, использующих Web API, - была создана с использованием GWT.

Волшебство GWT в основном заключается в компиляции Java-кода в код браузера на JavaScript, что позволяет разработчикам использовать привычную событийную модель программирования с возможностью прямого доступа к серверным данным. Большинство Java-программистов приходят в восторг при мысли, что больше нет необходимости писать код на JavaScript. Теперь они могут в полной мере использовать все преимущества строго типизированного языка, а так же средств отладки (например, Eclipse) для отлаживания Web-приложений на основе Ajax.

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

К счастью, GWT легко интегрируется с другими технологиями. Разработчики могут добавлять свой код на JavaScript напрямую в код, сгенерированный GWT. Таким образом, существует возможность разработки классов одновременно на Java и JavaScript, используя JSNI (JavaScript Native Interface).

JSNI

Документация по GWT описывает несколько способов использования JSNI. Во-первых, вы можете реализовывать клиентские методы, используя только JSNI. Во-вторых, вы можете использовать JSNI для написания оболочек вокруг существующего кода на JavaScript, что очень полезно при переносе существующих приложений на GWT. В-третьих, вы можете с помощью JSNI получать доступ к клиентскому коду на Java, который в любом случае компилируется в JavaScript, и наоборот. В общем, все, что вы можете делать на JavaScript, вы сможете реализовать, используя связку GWT и JSNI, без промежуточного представления в Java. Ниже приведены примеры использования JSNI.

Пример использования JSNI

Для рассмотрения возможностей JSNI начнем с одного из примеров, поставляемых вместе с GWT, а именно - KitchenSink. Несмотря на то, что KitchenSink изначально создавался для демонстрации компонентов пользовательского интерфейса, он так же хорошо подходит и для опытов с JSNI, т.к. весь код исполняется на клиентской стороне, без взаимодействия с сервером.

Для начала определим Java-метод, который будет реализован на JavaScript. Простейший пример метода - код, выводящий окошко с надписью "Hello World" - приведен в листинге 5.

Листинг 5. "Hello World" в JSNI

                
private native void blastName() /*-{
  alert("Hello world");
}-*/;

В качестве примера использования добавим вызов нашего метода в метод showInfo() класса KitchenSink, который вызывается при старте приложения. Код показан в листинге 6.

Листинг 6. Вызов JSNI-метода из кода на Java

                
private void showInfo() {
  show(list.find("Intro"), false);
  blastName(); // added JSNI method
}

Заметим, что GWT позволяет вызывать JSNI метод точно так же, как если бы он был написан на Java. Просто, не правда ли? Теперь скомпилируйте и запустите приложение в режиме хоста и вы увидите результат, подобный показанному на рисунке 1.

Рисунок 1. KitchenSink
KitchenSink

Теперь давайте сделаем что-нибудь более сложное, а именно, произведем обмен данными между кодом, написанным на Java, и кодом на JavaScript.

JSNI и Java-переменные

Чтобы применение JSNI приносило реальную пользу, нужна возможность реализовать обмен данными между Java-кодом и "родным" JavaScript. Это позволит сочетать преимущества GWT c гибкостью JavaScript. Взгляните на модифицированный вариант "Hello World", приведенный в листинге 7.

Листинг 7. JSNI and Java-переменные

                
public class KitchenSink implements EntryPoint, HistoryListener {

  private static final Sink.Images images = (Sink.Images) GWT.create(Sink.Images.class);

  protected SinkList list = new SinkList(images);
  private SinkInfo curInfo;
  private Sink curSink;
  private HTML description = new HTML();
  private VerticalPanel panel = new VerticalPanel();
  // new variable to be accessed in JSNI
  private String myVar = "Hello variables"; 

Вы можете получить доступ к переменной myVar , объявленной в Java, внутри метода, вызываемого через JSNI, как показано в листинге 8.

Листинг 8. Доступ к переменной myVar из JavaScript через JSNI

                
private native void blastName() /*-{
  var str = 
   this.@com.google.gwt.sample.kitchensink.client.KitchenSink::myVar;
  alert(str);
}-*/;

Перекомпилировав KitchenSink и нажав на ту же кнопку, что и раньше, вы увидите результат, подобный рисунку 2.

Рисунок 2. "Hello variables"
hello variables

Теперь вы видите, насколько легко пересылать данные между Java- и JavaScript-кодом. Теперь у вас есть все необходимое для органичной интеграции GWT с любой другой технологией, доступной через JavaScript. Например, XForms.

Заключение

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


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=17452