Платформа Google App Engine для Java-приложений : Часть 1. Знакомство

Узнайте о создании превосходных, отлично масштабируемых Java-приложений при помощи платформы App Engine от Google

Помните те времена, когда система Google App Engine была доступна только апологетам Python? Мрачные были деньки. Однако они канули в лету, когда в апреле 2009 г. Google Inc. открыла доступ к свой платформе облачных вычислений Java-разработчикам. Инструктор и автор статей по Java-технологиям Ричард Хайтауэр познакомит вас с этой интересной, надежной и отказоустойчивой платформой на страницах этой серии из трех частей. Прочитав первую статью, вы узнаете о преимуществах Google App Engine для Java в качестве платформы для развертывания вашего следующего приложения, которому требуется высокая степень масштабируемости. Кроме того, в статье демонстрируется использование встраиваемого модуля для Eclipse, созданного Google, при разработке двух демонстрационных приложений, одно из которых базируется на инструментарии Google Web Toolkit (GWT), а другое – на API Java-сервлетов. Вы узнаете о возможностях, открываемых Google App Engine для Java, как при создании нового приложения, так и при развертывании системы, к которой смогут обращаться до 5 млн человек в месяц (и это только в бесплатной версии!).

Ричард Хайтауэр (Richard Hightower), разработчик, ArcMind Inc.

Фотография автораРичард Хайтауэр (Rick Hightower) работает начальником отдела разработчиков в ArcMind Inc - компания, специализирующаяся на JSF, Spring и Hibernate. Он является соавтором известной книги Инструменты Java для экстремального программирования, в которой рассказывается, как применять экстремальное программирование в J2EE, и соавтором Struts для профессионалов.



29.06.2011

Реализовать идею – это все равно, что почесать, где чешется: сразу наступает облегчение. Будучи разработчиками программного обеспечения, мы проводим немало времени, обдумывая идеи самых разных приложений. Это захватывает, не правда ли? Однако основная проблема заключается в том, как преобразовать идею в успешный продукт. Законченная реализация идеи приносит чувство глубокого удовлетворения. В противном случае она так и останется зудом на вашем теле. 

Одна из причин, по которой многие проекты не доводятся до релиза, заключается в отсутствии необходимой инфраструктуры. Качественная поддержка инфраструктуры, как правило, требует наличия группы системных администраторов, администраторов баз данных и сетевых инженеров, что до недавних пор было по карману только корпоративным приложениям. Даже если вы заключаете контракт со сторонней компанией на хостинг вашего приложения, это не гарантирует решения всех проблем; например, что произойдет в случае неожиданного взлета популярности приложения, к которому вдруг начнет обращаться множество пользователей? Эта ситуация получила название эффекта Slashdot, который похоронил немало хороших идей только потому, что очень сложно предсказать скачки нагрузки на инфраструктуру.

К счастью, как вы теперь знаете, времена меняются. Инфраструктура Web-сервисов претерпела существенные изменения и теперь, благодаря облачным вычислениям, а также концепции "платформа-как-сервис" (PAAS), разработчикам стало значительно легче создавать, развертывать и распространять приложения. А главное, когда вы напишете очередной Twitter и развернете его на облачных серверах, он получит прекрасные возможности масштабирования. Это просто здорово!

Прочитав три статьи этой серии и выполнив примеры, вы поймете, почему концепции облачных вычислений и PAAS представляют собой столь важный шаг в эволюции подходов к созданию программного обеспечения. Кроме того, вы познакомитесь с увлекательной новой платформой под названием Google App Engine для Java, которая на данный момент находится на стадии предварительного релиза. После этого мы сразу перейдем к разработке первого демонстрационного приложения при помощи модуля Google App Engine для Eclipse. Это приложение будет использовать поддержку API сервлетов в App Engine, в то время как следующее приложение будет использовать GWT. В следующей статье мы создадим небольшое приложение для управления контактами с использованием поддержки сервлетов и GWT в App Engine. Наконец, в третьей статье на примере ранее созданного приложения будет рассмотрена поддержка хранилищ Java-объектов в App Engine, которая основывается на таких технологиях, как JDO (Java Data Objects) и JPA (Java Persistence API).

Впрочем, довольно слов, пора переходить к делу.

О платформе Google App Engine для Java

Google (кстати, не они ли являются создателями популярного поискового сервиса?) выпустили первый релиз платформы Google App Engine в апреле 2008 г. Однако к глубокому разочарованию Java-разработчиков, первоначальная версия платформы предназначалась исключительно для создателей приложений на Python, т.е. людей, которые уверены, что лучший способ выделения блоков кода заключается в использовании пробелов и знаков табуляции (поверьте, что как автор книги о Python, я знаю, о чем говорю). К счастью, по многочисленным просьбам Google устранил этот недостаток, выпустив версию платформы для Java в апреле 2009 г.

Google App Engine для Java предоставляет полный набор средств создания корпоративных Java-систем: простой в использовании графический интерфейс на основе Ajax, модули для Eclipse, а также серверную часть App Engine. Легкость применения и широкий набор готовых средств разработки являются важными преимуществами данной платформы и других решений на основе облачных вычислений.

Создание приложения при помощи App Engine подразумевает использование ресурсов Google для хранения и выборки объектов Java-классов. Хранение данных реализовано на основе системы BigTable, однако интерфейсы JDO и JPA позволяют писать полностью независимый от нее код. Более того, Google поддерживает многие стандартизованные API, поэтому код вашего приложения не будет на 100% привязан к платформе Google App Engine.

Работа App Engine базируется на следующих стандартных API:

  • java.net.URL для обращения к сетевым сервисам поверх протоколов HTTP and HTTPS;
  • JavaMail для отправки почтовых сообщений;
  • интерфейсе JCache (JSR 107) для Memcache, предоставляющем быстрое, распределенное хранилище временных данных, которые используются при кэшировании результатов запросов и вычислений.

Развертывание App Engine для Java в WebSphere/DB2

Представители Google и IBM® развернули демонстрационное приложение на основе App Engine в DB2®/WebSphere®непосредственно в момент анонсирования выпуска данной платформы. В настоящее время IBM работает над поддержкой низкоуровневых API Google в таких продуктах, как Tivoli® LDAP и DB2, чтобы приложения, созданные для App Engine, могли выполняться в среде WebSphere/DB2.

Кроме того, App Engine поддерживает следующие прикладные сервисы:

  • авторизация и аутентификация пользователя;
  • CRON
  • импорт/экспорт данных;
  • доступ к данным сетевых экранов.

Возможность импорта и экспорта данных играет важную роль при переносе данных из других источников в приложение на основе App Engine. Это еще один пример того, как вы можете снизить зависимость приложения от данной платформы. Поддержка CRON заключается в возможности перехода по внутреннему URL в соответствии с заданным расписанием. Это весьма удобный сервис, к тому же не очень сильно привязанный к App Engine. Механизм аутентификации и авторизации, в свою очередь, является специфичным для данной платформы, однако ничто не мешает вам создать специальный фильтр сервлетов, аспект или собственный модуль Spring Security для абстрагирования от App Engine.

Создание первого Java-приложения для App Engine

Дочитав до этого момента, вы уже готовы приступить к созданию вашего первого приложения для App Engine. Последнее, что необходимо сделать – это установить модуль Google App Engine для Eclipse.

Открыв среду разработки Eclipse, вы увидите три новые кнопки на панели инструментов рядом со знакомой кнопкой Printer: синий кружок с буквой g, красный ящичек с буквой G и авиадвигатель (эмблема Google App Engine для Java). Кнопки изображены на рисунке 1.

Рисунок 1. Новые кнопки на панели инструментов Eclipse
Новые кнопки на панели инструментов Eclipse

Эти кнопки служат для выполнения следующих действий.

  • Синяя кнопка вызывает мастер создания проекта Java-приложения для App Engine.
  • Красная кнопка служит для компиляции проектов, использующих GWT.
  • Кнопка с авиадвигателем необходима для развертывания проекта на основе App Engine.

Мы будем использовать мастер для создания двух новых проектов, один из которых будет использовать сервлеты, а второй – GWT. Красная кнопка понадобится при компиляции второго проекта, а авиадвигатель – после того, как приложение будет готово к развертыванию.

Приступим к созданию проекта приложения App Engine. Вначале нажмите на круглую синюю кнопку для вызова мастера. Далее создайте приложение с именем SimpleServletApp в пакете aej.example, как показано на рисунке 2.

Рисунок 2. Пример создания нового проекта
Пример создания нового проекта

Обратите внимание, что в этом проекте снят флажок поддержки GWT. После выполнения этих действий мастер создания проекта инициализирует простое приложение на основе сервлетов, которое будет включать всего один простой сервлет с функциональностью а-ля "Здравствуй мир!". Содержимое проекта показано на рисунке 3.

Рисунок 3. Проект SimpleServletApp
Проект SimpleServletApp

Как видите, в только что созданный проект были автоматически добавлены ряд JAR-файлов, а именно:

  • datanucleus-*.jar: служит для доступа к хранилищу данных App Engine при помощи JDO или низкоуровневого API BigTable;
  • appengine-api-sdk.1.2.0.jar: служит для доступа к нестандартным сервисам App Engine, например, Security;
  • geronimo-*.jar: служит для использования стандартных API, таких как API управления транзакциями в Java ( Java Transaction Management API – JTA) и JPA;
  • jdo2-api-2.3-SNAPSHOT.jar: необходим при использовании API JDO.

API App Engine для хранения данных, а также некоторые другие прикладные сервисы App Engine будут рассматриваться, начиная со второй статьи этой серии.

Также следует обратить внимание на файл конфигурации контейнера времени выполнения Google App Engine под названием appengine.xml. В данном примере этот appengine.xml используется для настройки файла logging.properties, в котором задаются настройки журналирования в приложениях на основе App Engine.

Первый запуск приложения для App Engine на основе сервлетов

Завершив конфигурирование при помощи мастера, вы увидите голый каркас сервлет-приложения в стиле "Здравствуй мир!" для App Engine. Обратите внимание на код приложения, чтобы понять, как оно должно запускаться при помощи модуля App Engine для Eclipse. Основной точкой входа является класс SimpleServletAppServlet, приведенный в листинге 1.

Листинг 1. Класс SimpleServletAppServlet
package gaej.example;

import java.io.IOException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class SimpleServletAppServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("Hello, world");
    }
}

Этот сервлет связан с URI /simpleservletapp  в файле web.xml (листинг 2).

Листинг 2. Содержимое файла web.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <servlet>
        <servlet-name>simpleservletapp</servlet-name>
        <servlet-class>gaej.example.SimpleServletAppServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>simpleservletapp</servlet-name>
        <url-pattern>/simpleservletapp</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Мастер также создал файл index.html, содержащий ссылку на новый сервлет, как показано в листинге 3.

Листинг 3. Файл index.html, автоматически сгенерированный мастером создания проекта
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- Использование DOCTYPE Transitional в HTML 4.01
     в начале файла переводит браузер в режим обратной
     совместимости ("Quirks Mode"). Существует возможность
     использования стандартного режима, однако это может
     привести к некоторым различиям при отображении страниц -->

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--                                           -->
    <!-- Можно задавать любой заголовок            -->
    <!--                                           -->
    <title>Hello App Engine</title>
  </head>

  <!--                                           -->
  <!-- Тег body может содержать произвольный     
       фрагмент HTML.                            -->
  <!-- Вы также можете оставить его пустым, если -->
  <!-- вы хотите создать полностью динамический  -->
  <!-- интерфейс.                                -->
  <body>
    <h1>Hello App Engine!</h1>
    
    <table>
      <tr>
        <td colspan="2" style="font-weight:bold;">Available Servlets:</td>        
      </tr>
      <tr>
        <td><a href="simpleservletapp"/>SimpleServletAppServlet</td>
      </tr>
    </table>
  </body>
</html>

С какими технологиями совместим App Engine для Java?

На сайте Google приведен список технологий, которые работают вместе с App Engine для Java без всяких проблем (см. раздел Ресурсы). В частности, App Engine поддерживает множество языков для JVM, в том числе BeanShell, Groovy, Scala, JRuby, Jython и Rhino. Кроме того, многие существующие инфраструктуры могут работать вместе с App Engine без дополнительной настройки, поскольку данная платформа поддерживает множество стандартных API Java SE и Java EE, таких как сервлеты, JSP, JPA, JavaMail и JAXP (Java API for XML Processing). Например, вы можете использовать Spring, хотя вам придется преодолеть определенные сложности с Spring ORM. Tapestry, Wicket, DWR, Tiles, SiteMesh и Grails будут работать без проблем, а Struts 2 – после добавления небольшой заплатки. Примерами инфраструктур, которые не будут работать с App Engine, являются Hibernate и JDBC (из-за отсутствия поддержки реляционных баз данных), JMX, Java WebServices, JAX-RPC, JAX-WS, JCA, JNDI, JMS, EJB и Java RMI.

Итак, у нас есть простое Java-приложение на основе сервлетов, использующее несколько других API. Именно в этом вся прелесть App Engine: вся его функциональность доступна через стандартные интерфейсы, что позволяет поддерживать множество различных технологий платформы Java.

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

Для запуска приложения при помощи модуля App Engine для Eclipse следует нажать правой кнопкой мыши на проекте, выбрать пункт Run As, а затем кликнуть на круглую синюю кнопку рядом с надписью "Web-application" (пример показан на рисунке 4).

Рисунок 4. Запуск сервера разработки приложений для App Engine
Запуск сервера разработки приложений для App Engine

Теперь, указав адрес http://localhost:8080/simpleservletapp в браузере, вы должны увидеть сообщение "Hello World", выведенное нашим приложением.

GWT и традиционные Web-приложения на Java

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

Создание Java-приложения на базе GWT для Google App Engine

Итак, вы получили представление о том, что представляет собой простое Java-приложение для App Engine на основе сервлетов, поэтому можно перейти к созданию приложения GWT при помощи подключаемого модуля Eclipse. Вначале кликните на круглую синюю кнопку на панели инструментов Eclipse для вызова мастера создания проекта GWT. После этого выберите пункт GWT, как показано на рисунке 5.

Рисунок 5. Использование мастера создания проекта простого GWT-приложения для Google App Engine
Использование мастера создания проекта простого GWT-приложения для Google App Engine

Как видно из рисунка 6, мастер App Engine генерирует больше кода для GWT-приложения, чем для приложения на основе сервлетов. Наше демонстрационное приложение включает графический интерфейс, который взаимодействует с сервисом, генерирующим приветственное сообщение.

Рисунок 6. Компоненты GWT-приложения
Компоненты GWT-приложения

Обратите внимание, что GWT-приложение включает дополнительный JAR-файл (gwt-servlet.jar), который не требовался в случае использования сервлетов.

Кроме того, были автоматически созданы следующие компоненты приложения:

  • src/gaej/example: SimpleGWTApp.gwt.xml – дескриптор модуля GWT;
  • src/gaej.example.server: GreetingServiceImpl.java – реализация сервиса, генерирующего приветственное сообщение;
  • src/gaej.example.client: GreetingService.java – синхронный API для приветствующего сервиса;
  • src/gaej.example.client: GreetingServiceAsync.java – асинхронный API для приветствующего сервиса;
  • src/gaej.example.client: SimpleGWTApp.java – главная точка входа в приложение, которая также необходима для компиляции графического интерфейса;
  • war/WEB-INF: web.xml – дескриптор развертывания, отвечающий за конфигурирование GreetingServiceImpl
  • war: SimpleGWTApp.html – HTML-страница, отображающая интерфейс GWT-приложения;
  • war: SimpleGWTApp.css – таблица стилей для GWT-интерфейса.

Перед тем как перейти к архитектуре и реализации приложения, давайте посмотрим, что происходит при его запуске. Для запуска приложения кликните на квадратной красной кнопке на панели инструментов, а затем нажмите кнопку Compile. Далее нажмите правой кнопкой мыши на проекте и так же, как и ранее, выберите пункт меню Run As —> Web Application. В отличие от предыдущего приложения, в этот раз запустится консоль хост-режима GWT и появится окно браузера. Теперь вы можете ввести свое имя и увидеть результат, подобный показанному на рисунке 7.

Рисунок 7. Запуск демонстрационного приложения на базе GWT
Запуск демонстрационного приложения на базе GWT

Далее мы рассмотрим внутреннее устройство демонстрационного GWT-приложения. Если вас интересует более подробная информация о GWT, например руководство по GWT, обратитесь к разделу Ресурсы.

Внутри GWT-приложения

Учитывая заданные настройки, модуль GWT для Eclipse генерирует приложение-стартёр, которое включает HTML-интерфейс (SimpleGWTApp.html, приведенный в листинге 10), загружающий файлы simplegwtapp.js и simplegwtapp.nocache.js. Эти файлы содержат код на JavaScript, полученный при компиляции Java-кода, который находится в директории src, в пакете gaej.example.client (листинги 6, 7 и 8).

Начальной точкой генерации графического интерфейса является файл gaej.example.client.SimpleGWTApp, показанный в листинге 8. Этот класс создает графические компоненты GWT-интерфейса и связывает их с DOM-элементами HTML-страницы в файле SimpleGWTApp.html (листинг 10). Эта страница описывает два элемента DOM: nameFieldContainer и sendButtonContainer, являющиеся колонками в таблице. Класс SimpleGWTApp использует метод RootPanel.get("nameFieldContainer")  для доступа к панели с этими элементами DOM и меняет их на элементы GUI. Затем класс описывает поле для ввода текста и кнопку, которые используются для ввода имени и получения соответствующего приветствия (листинг 10).

GWT узнает о том, что класс SimpleGWTApp  является точкой входа в приложение из файла SimpleGWTApp.gwt.xml, в котором задается элемент entry-point.

Класс SimpleGWTApp связывает кнопку sendButton с методом greetServer интерфейса GreetingService, который находится в файле src/gaej.example.client.GreetingService.java (листинг 6).

По своей природе Ajax является асинхронной технологией, поэтому GWT создает асинхронные интерфейсы для обращения к удаленным сервисам. В частности, класс SimpleGWTApp использует асинхронный интерфейс, находящийся в файле src/gaej.example.client.GreetingServiceAsync.java (листинг 7). Он содержит метод greetServer, который реализуется классом GreetingServiceImpl, находящимся в файле src/gaej.example.server.GreetingServiceImpl.java (листинг 5). Этот метод возвращает приветственное сообщение, которое затем отображается в диалоговом окне, созданном SimpleGWTApp.

Главная точка входа в приложение объявляется в дескрипторе GWT-модуля. В нашем случае таковой является файл gaej.example.client.SimpleGWTApp (листинг 4).

Листинг 4. Дескриптор GWT-модуля (src/gaej/example/SimpleGWTApp.gwt.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN"

"http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/
  distro-source/core/src/gwt-module.dtd">


<module rename-to='simplegwtapp'>
  <!-- Наследование базовой функциональности Web Toolkit.         -->
  <inherits name='com.google.gwt.user.User'/>

  <!-- Наследование таблицы стилей GWT по умолчанию.              -->
  <!-- Вы можете изменить оформление GWT-приложения,              -->
  <!-- раскомментировав любую из строк ниже.                      -->
  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->

  <!-- Наследование других модулей                                -->

  <!-- Указание класса, выполняющего функцию точки входа          -->
  <entry-point class='gaej.example.client.SimpleGWTApp'/>
</module>

Реализация приветствующего сервиса заключена в классе GreetingServiceImpl, код которого приведен в листинге 5. Он выполняется на стороне сервера, будучи доступным для клиентских обращений через механизм вызовов удаленных процедур.

Листинг 5. Реализация приветствующего сервиса (src/gaej.example.server.GreetingServiceImpl.java)
package gaej.example.server;

import gaej.example.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * Серверная часть реализации RPC-сервиса
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
        GreetingService {

    public String greetServer(String input) {
        String serverInfo = getServletContext().getServerInfo();
        String userAgent = getThreadLocalRequest().getHeader("User-Agent");
        return "Hello, " + input + "!<br><br>I am running " + serverInfo
                + ".<br><br>It looks like you are using:<br>" + userAgent;
    }
}

GreetingService, показанный в листинге 6, играет роль интерфейса для клиентских вызовов удаленных процедур.

Листинг 6. Синхронный API (src/gaej.example.client.GreetingService.java)
package gaej.example.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * Клиентская заглушка для RPC-сервиса
 */
@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
    String greetServer(String name);
}

Интерфейс GreetingServiceAsync используется непосредственно клиентами, как показано в листинге 7. Каждый метод принимает на вход объект обратного вызова, благодаря которому клиенты узнают о завершении работы процедуры. Технология GWT базируется на Ajax, которая использует асинхронные вызовы для того, чтобы не блокировать клиентский код на время выполнения серверных методов. Блокирование свело бы на нет практически всю пользу от использования Ajax.

Листинг 7. Асинхронный API (src/gaej.example.client.GreetingServiceAsync.java)
package gaej.example.client;

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

/**
 * Асинхронный аналог <code>GreetingService</code>.
 */
public interface GreetingServiceAsync {
    void greetServer(String input, AsyncCallback<String> callback);
}

Наиболее интересная часть кода приложения заключена в классе SimpleGWTApp (листинг 8). Он регистрирует события GUI и оправляет клиентские запросы сервису GreetingService.

Листинг 8. Стартовый класс приложения, инициализирующий графический интерфейс (src/gaej.example.client.SimpleGWTApp.java)
package gaej.example.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Классы, играющие роль точки входа, должны иметь метод <code>onModuleLoad()</code>.
 */
public class SimpleGWTApp implements EntryPoint {
    /**
     * Это сообщение показывается пользователю, если сервер 
     * недоступен или возвращает ошибку.
     */
    private static final String SERVER_ERROR = "An error occurred while "
            + "attempting to contact the server. Please check your network "
            + "connection and try again.";

    /**
     * Создание прокси-объекта для взаимодействия с серверной частью
     * сервиса Greeting
     */
    private final GreetingServiceAsync greetingService = GWT
            .create(GreetingService.class);

    /**
     * Точка входа в приложение
     */
    public void onModuleLoad() {
        final Button sendButton = new Button("Send");
        final TextBox nameField = new TextBox();
        nameField.setText("GWT User");

        // Добавление имен стилей к виджетам
        sendButton.addStyleName("sendButton");

        // Добавление nameField и sendButton к RootPanel
        // Вызов RootPanel.get() для получения элемента body
        RootPanel.get("nameFieldContainer").add(nameField);
        RootPanel.get("sendButtonContainer").add(sendButton);

        // Передача фокуса ввода полю name при запуске приложения
        nameField.setFocus(true);
        nameField.selectAll();

        // Создание всплывающего диалогового окна
        final DialogBox dialogBox = new DialogBox();
        dialogBox.setText("Remote Procedure Call");
        dialogBox.setAnimationEnabled(true);
        final Button closeButton = new Button("Close");
        // Идентификаторы виджетов можно задавать через соответствующие элементы
        closeButton.getElement().setId("closeButton");
        final Label textToServerLabel = new Label();
        final HTML serverResponseLabel = new HTML();
        VerticalPanel dialogVPanel = new VerticalPanel();
        dialogVPanel.addStyleName("dialogVPanel");
        dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
        dialogVPanel.add(textToServerLabel);
        dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
        dialogVPanel.add(serverResponseLabel);
        dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
        dialogVPanel.add(closeButton);
        dialogBox.setWidget(dialogVPanel);

        // Добавление обработчика для закрытия DialogBox
        closeButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                dialogBox.hide();
                sendButton.setEnabled(true);
                sendButton.setFocus(true);
            }
        });

        // Создание обработчиков для sendButton и nameField
        class MyHandler implements ClickHandler, KeyUpHandler {
            /**
             * Этот метод вызывается при нажатии на кнопку sendButton.
             */
            public void onClick(ClickEvent event) {
                sendNameToServer();
            }

            /**
             * Этот метод вызывается при вводе текста в поле nameField.
             */
            public void onKeyUp(KeyUpEvent event) {
                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
                    sendNameToServer();
                }
            }

            /**
             * Передача значения поля nameField серверу и ожидание отклика
             */
            private void sendNameToServer() {
                sendButton.setEnabled(false);
                String textToServer = nameField.getText();
                textToServerLabel.setText(textToServer);
                serverResponseLabel.setText("");
                greetingService.greetServer(textToServer,
                        new AsyncCallback<String>() {
                            public void onFailure(Throwable caught) {
                                // Показ сообщения об ошибке RPC пользователю
                                dialogBox
                                        .setText("Remote Procedure Call - Failure");
                                serverResponseLabel
                                        .addStyleName("serverResponseLabelError");
                                serverResponseLabel.setHTML(SERVER_ERROR);
                                dialogBox.center();
                                closeButton.setFocus(true);
                            }

                            public void onSuccess(String result) {
                                dialogBox.setText("Remote Procedure Call");
                                serverResponseLabel
                                        .removeStyleName("serverResponseLabelError");
                                serverResponseLabel.setHTML(result);
                                dialogBox.center();
                                closeButton.setFocus(true);
                            }
                        });
            }
        }

        // Добавление обработчика для отправки имени пользователя серверу
        MyHandler handler = new MyHandler();
        sendButton.addClickHandler(handler);
        nameField.addKeyUpHandler(handler);
    }
}

Дескриптор развертывания (файл web.xml, приведенный в листинге 9) служит для описания интерфейса GreetingService в качестве сервлета Web-приложения. Ему присваивается имя /simplegwtapp/greet, чтобы класс SimpleGWTApp мог загружать и вызывать его методы при выполнении приложения. Кроме того, в дескрипторе развертывания указывается, что SimpleGWTApp.html является стартовой страницей приложения, а, следовательно, должна загружаться при каждом его запуске.

Листинг 9. Дескриптор развертывания, содержащий описание GreetingServiceImpl (war/WEB-INF/web.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <!-- Страница по умолчанию -->
  <welcome-file-list>
    <welcome-file>SimpleGWTApp.html</welcome-file>
  </welcome-file-list>
 
  <!-- Сервлеты -->
  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>gaej.example.server.GreetingServiceImpl</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/simplegwtapp/greet</url-pattern>
  </servlet-mapping>

</web-app>

HTML-интерфейс приложения находится в файле SimpleGWTApp.html, показанном в листинге 10. Именно эта страница загружает скрипты simplegwtapp.js и simplegwtapp.nocache.js, содержащие JavaScript-код, который был сгенерирован GWT на основе Java-кода приложения. Как было упомянуто ранее, исходный Java-код интерфейса находится в директории src, в пакете gaej.example.client (листинги 6, 7 и 8).

Листинг 10. HTML-страница, отображающая графический интерфейс на базе GWT (war/SimpleGWTApp.html)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- Использование DOCTYPE Transitional в HTML 4.01
     в начале файла переводит браузер в режим обратной
     совместимости ("Quirks Mode"). Существует возможность
     использования стандартного режима, однако это может
     привести к некоторым различиям при отображении страниц -->

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!--                                                               -->
    <!-- Страницы CSS можно поместить внутрь этого файла,
         чтобы уменьшить число загружаемых файлов  -->
    <!--                                                               -->
    <link type="text/css" rel="stylesheet" href="SimpleGWTApp.css">

    <!--                                           -->
    <!-- Можно задавать любой заголовок            -->
    <!--                                           -->
    <title>Web Application Starter Project</title>
    
    <!--                                           -->
    <!-- Этот скрипт загружает скомпилированный модуль.   -->
    <!-- Все мета-теги GWT должны быть добавлены   -->
    <!-- до этой строки.                           -->
    <!--                                           -->
    <script type="text/javascript" language="javascript" 
  src="simplegwtapp/simplegwtapp.nocache.js"></script>
  </head>

  <!--                                           -->
  <!-- Тег body может содержать произвольный     
       фрагмент HTML.                            -->
  <!-- Вы также можете оставить его пустым, если -->
  <!-- вы хотите создать полностью динамический  -->
  <!-- интерфейс.                                -->
  <body>

    <!-- Этот необязательный фрагмент служит для поддержки истории -->
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' 
  style="position:absolute;width:0;height:0;border:0"></iframe>

    <h1>Web Application Starter Project</h1>

    <table align="center">
      <tr>
        <td colspan="2" style="font-weight:bold;">Please enter your name:</td> 
      </tr>
      <tr>
        <td id="nameFieldContainer"></td>
        <td id="sendButtonContainer"></td>
      </tr>
    </table>
  </body>
</html>

При использовании GWT вы управляете внешним видом приложения при помощи стилей CSS (листинг 11).

Листинг 11. Таблицы стилей для интерфейса на базе GWT (war/SimpleGWTApp.css)
/** Сюда вы можете добавить CSS-стили для вашего приложения. */


/** Эти стили были созданы для демонстрационного приложения
   (удалите их при создании собственного приложения) */
h1 {
  font-size: 2em;
  font-weight: bold;
  color: #777777;
  margin: 40px 0px 70px;
  text-align: center;
}

.sendButton {
  display: block;
  font-size: 16pt;
}

/** Большинство виджетов GWT включают собственный стиль */
.gwt-DialogBox {
  width: 400px;
}

.dialogVPanel {
  margin: 5px;
}

.serverResponseLabelError {
  color: red;
}

/** Идентификатор задается при помощи метода widget.getElement().setId("idOfElement") */
#closeButton {
  margin: 15px 6px 6px;
}

Развертывание приложения на платформе Google App Engine

Закончив работу над нашим шедевром (вы же не сомневаетесь, что всем жизненно необходимо удобное приветствующее приложение?), можно перейти к его развертыванию. Основной смысл использования платформы Google App Engine заключается в том, что приложение можно развернуть на инфраструктуре Google, что значительно облегчает масштабирование приложения. Google App Engine специально проектировался как платформа для создания приложений, число пользователей которых может достигать миллионов без создания серьезных проблем для инфраструктуры (так утверждается на домашней странице App Engine). Для использования этой инфраструктуры вам понадобится учетная запись Google App Engine для Java.

Как это часто бывает, первая попытка предоставляется бесплатно. Бесплатная версия App Engine предоставляет развернутым Java-приложениям достаточно процессорного времени, ширины каналов и объема дисковой памяти для обслуживания примерно 5 млн посетителей. После этого вам придется платить в соответствии с интенсивностью использования системы. Кстати говоря, учтите, что все цифры на момент написания этой статьи относятся к предварительному релизу Google App Engine для Java.

После получения учетной записи вы должны увидеть пустой список приложений на сайте App Engine для Java. Нажмите на кнопку Create New Application ("создать новое приложение"), после чего появится форма ввода, подобная показанной на рисунке 8. Далее введите уникальное имя и описание приложения, и вы должны получить подтверждение с его идентификатором.

Этот идентификатор, который не может быть изменен, также находится в файле app.yaml вашего приложения. Если вы используете аутентификацию Google в вашем приложении, то строка "GAEj Article For Rick Part 1" будет отображаться на страницах "Sign In" ("вход") при каждом обращении. При развертывании демонстрационного приложения при помощи модуля App Egnine для Eclipse следует использовать идентификатор gaejarticleforrick.

Рисунок 8. Создание нового приложения для App Engine
Создание нового приложения для App Engine

Указание идентификатора приложения — это все, что требуется при его развертывании из Eclipse. Далее нажмите на кнопку на панели инструментов, которая напоминает логотип Google App Egnine (авиадвигатель с крыльями и хвостом). Пример показан на рисунке 1.

Перед нажатием на кнопку Deploy ("развертывание") необходимо убедиться, что типом проекта является "App Engine for Java project", как показано на рисунке 9. После этого следует ввести параметры учетной записи Google, т.е. ваш адрес электронной почты и имя пользователя.

Рисунок 9. Развертывание проекта
Развертывание проекта

Диалоговое окно, показанное на рисунке 10, содержит ссылку "App Engine Project setting" (настройки проекта для App Engine), которая также находится в файле свойств проекта. Кликните на этой ссылке и введите идентификатор приложения, т.е. в нашем случае gaejarticleforrick, как показано на рисунке 10. Указав идентификатор, нажмите OK, а затем – Deploy.

Рисунок 10. Настройки проекта для Google App Engine
Настройки проекта для Google App Engine

После развертывания приложения к нему можно будет обращаться по адресу http://<идентификатор приложения>.appspot.com/. Таким образом, демонстрационное приложение к этой статье можно увидеть, перейдя по ссылке http://gaejarticleforrick.appspot.com/.

Заключение

На этом мы заканчиваем первую часть серии, посвященной платформе Google App Engine для Java. К этому моменту вы получили общее представление о платформе, а также сделали первые шаги в использовании модуля App Engine для Eclipse. В этой статье было продемонстрировано создание двух небольших приложений (одно на основе сервлетов, а второе – на основе GWT), последнее из которых было развернуто на платформе Google App Engine.

В этой статье на примерах была показана работа с инструментами, облегчающими создание и развертывание масштабируемых (в теории – до масштабов Facebook или YouTube) приложений. В следующей части мы продолжим рассмотрение возможностей, доступных Java-разработчикам, использующим Google App Engine для Java. Для этого мы создадим новое Java-приложение для управления контактной информацией. Оно также будет занимать центральное место в примерах к третьей статье, главной темой которой станут хранилище данных App Engine и поддержка средств создания графического интерфейса пользователя.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

  • Подпишитесь на сообщения дискуссионной группы App Engine для Java, чтобы иметь возможность задавать вопросы и помогать другим разработчикам в процессе изучения платформы Google App Engine. (EN)

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Мобильные приложения, Open source
ArticleID=696376
ArticleTitle=Платформа Google App Engine для Java-приложений : Часть 1. Знакомство
publish-date=06292011