16 октября 2009 г.

Клиент для Google Wave в виде Java Web Application


Автор: zokotuhaFly (aka shaman.sir)
Источник: http://habrahabr.ru/blogs/google/72235/ (перепечатывается здесь с любезного разрешения автора)

Клиент для Google Wave в виде Java Web Application + небольшая история

Здравствуйте.

[Здесь должен быть абзац с небольшой историей, который я поместил в постскриптум, дабы не создавать ненужных ощущений до прочтения]

sametimed

Итак, я написал небольшой проект на Java, который представляет собой клиент к Google Wave, который, в свою очередь, вы можете расширить необходимыми вам возможностями. Визуально выглядит он не очень презентабельно (впрочем, а-ля Windows 3.11, почему бы и нет), поскольку веб-дизайнер из меня не очень хороший, однако абсолютно за весь исходный код я отвечаю головой :). Так, например, требующиеся для отображения CSS-стили при этом выглядят максимально понятно, а XHTML-структура максимально упрощена (не в ущерб стандартам) для того, чтобы настоящий дизайнер мог развернуться и сделать действительно красиво :).

sametimed в работе

Сайт, исходные коды, и war-пакет с текущим состоянием проекта находятся по адресу http://code.google.com/p/sametimed

Сейчас у меня нет под рукой общедоступного хостинга, чтобы я мог прямо вот так запустить проект и дать поиграться с ним не отходя от хабра, однако, я могу предложить вам видео (на vimeo), демонстирующее его основные возможности, что, думаю, тоже вполне ничего, а запустить проект вы сможете сами, благо подробные инструкции есть на сайте проекта, а развёрнутые пояснения и подробное описание работы (и руководство к расширению возможностей) — внутри…



Установка


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

Чуть более подробные инструкции как его запустить сам по себе или в виде рабочего проекта для Eclipse представлены на странице проекта. Здесь же я рассмотрю структуру кода и опишу как он действует (пока без что UML-диаграмм, извините, по мере возможности я их добавлю).

Общая концепция


Здесь под сочетанием «серверная сторона/часть» подразумевается не сервер wave-protocol, а серверная строна веб-приложения.

Поскольку в wave-protocol сейчас существует только консольный клиент, релизованный в виде jar-приложения, основной вопрос состоит в своевременной передаче информации с клиента на серверную часть и наоборот.

Посему стало необходимо ввести два понятия:
  • Команда: отправляется с клиента на сервер, требует «открыть волну», «добавить участника», «отменить действие», «сказать привет» и т.п., отправляется по действию пользователя.
  • Сообщение: отправляется с сервера на клиент, сообщает о том, что «кто-то пригласил в волну», «sonya ответила привет», «добавился участник», «произошла ошибка», отправляется при любом обновлении.

При этом, команду с клиента можно отправить сразу, сильно не задумываясь о нагрузке на сервер, а вот сообщения об обновлениях требуется отсылать только по факту происшествия. Однако, на клиенте находится javascript, который без сложных приспоcоблений не может осуществлять такие вещи. Здесь потребовался Reverse Ajax, вернее его реализация для Java — библиотека DWR (Direct Web Remoting), она позволяет вызывать функцию на клинете с сервера в тот момент, когда решит сервер, а не клиент. Их сайт рассказывает о всех возможностях, которые вовсе не ограничены данным применением, но для проекта, как я уже сказал, из всех возможностей я использовал только эту.

Команды и сообщения передаются в виде XML, а содержимое сообщений об обновлениях в виде JSON, засчёт чего в построении интерфейса участвует только Javascript (я использовал JQuery), а серверная сторона даже не задумывается о существовании UI.

(для серверной стороны в проекте есть интерфейс Renderer, реализация которого вызывается при необходимых обновлениях, но он предназначен как раз для случаев вроде консольного клиента)

Описание процесса, происходящего в текущей версии


При запуске клиента, вы видите страницу с полем для ввода юзернейма и единственной кнопкой. Wave-protocol сервер при этом должен быть запущен. При нажатии на кнопку введённый вами юзернейм передаётся в сервлет (GetClientViewServlet), который подключает вас «к волне», и возвращает всю структуру (модель) клиента в виде JSON. JQuery на клиентской стороне строит весь интерфейс вейвлета. Если вы нажмёте кнопку ещё раз, вы запросите ещё один вейвлет, при этом между собой они будут различаться по внутреннему ID (сгенерированному автоматически), указанному на синей полоске в скобках. По этому ID и сервер и клиент определяют, к какому клиенту относится команда и/или сообщение.

Одновременно с этим DWR начинает ожидать вестей об обновлениях, а вы в это время можете ввести любую из доступных команд в поле консоли и нажать «send». Например, создать волну командой «\new», открыть её командой «\open » и что-нибудь сказать, набрав просто текст (как в скайпе). При нажатии на кнопку «send» отправляется POST-запрос к другому сервлету (CommandsReceiverServlet), который получает сгенерированную в виде XML команду и тут же её выполняет, передавая данные серверу wave-protocol.

Обновления в данный момент приходят с серверной стороны (и от сервера wave-protocol) в виде XML-сообщения (на клиентской стороне есть обработчик, который вызывается при получении новых сообщений), в котором содержится алиас изменившейся модели (например, «chat», «inbox», «userslist», «errors» или «editor») и её содержимое в виде JSON, которое тут же обрабатывается и обновляет соответствующую часть вейвлета.

Как видите, всё до невозможности просто.

Структура проекта и возможности для расширения



Java:


  • name.shamansir.sametimed.wave Все классы, лежащие «снаружи» и относящиеся к клиенту непосредственно; здесь находятся абстрактные классы AUpdatingWavelet и ADocumentsWavelet — определяющие структуру соответствующего типа вейвлетов (обновляющийся вейвлет и его расширение, вейвлет содержащий документы). Класс SimpleWavelet служит примером такой реализации. Класс WavesClient занимается обработкой команд и именно он возвращает модель содержащегося в нём вейвлета вGetClientViewServlet.
  • name.shamansir.sametimed.wave.messaging Все, что относится к командам и сообщениям. Идентификаторы команд/сообщений вCommandID/MessageTypeID, сами классы Command и UpdateMessage, сервлет-обработчик CommandsReceiverServlet.
  • name.shamansir.sametimed.wave.model Классы, описывающие модель вейвлета. Они содержат описание каждой суб-модели, вроде списка участников, чата или текстового документа. И ModelID, описывающий возможные модели с абстрактным классом AModel, конечно. Плюс,ModelFactory, фабрика моделей.
  • name.shamansir.sametimed.wave.model.base Значения моделей, вроде «набора строк чата», «набора блоков текста в документе», «списка доступных волн» и т.д. Именно в этих классах описывается преобразование в JSON.
  • name.shamansir.sametimed.wave.model.base.atom То, из чего состоят значения, если это необходимо для их структуры — «строка чата», «блок текста», «идентификатор волны»
  • name.shamansir.sametimed.wave.model.base.chat Вейвлет с функцией чата и клиент для него
  • name.shamansir.sametimed.wave.model.base.editor Вейвлет с поддержкой редактируемого документа, на данный момент не имплементирован, поэтому отключен
  • name.shamansir.sametimed.wave.render Классы, относящиеся к рендерингу Здесь находится тот самый класс JSUpdatesListener, который средствами DWR вызывает функцию обновления на клиенте.

Самый логичный способ расширения — имплементация класса ADocumentsWavelet или расширение класса WaveletWithChat. Поскольку, в наиболее вероятном случае, вы будете оперировать понятием «документ» (А чат или что-либо другое, как раз являются документами), то именно такой способ должен подойти вам лучше всего. Также вам понадобится задуматься о модели данного документа (создав соответсвующий тип, реализующий AModel, добавить id модели в тип ModelID и генерацию модели в ModelFactory).

Если документ не будет обрабатывать какие-либо новые команды, то этого достаточно — можно заменить в GetClientViewServlet возвращаемый вейвлет на ваш собственный и вуаля!.. Ах, да, ещё генерация UI на клиенте, но об этом ниже.

Если же необходимы свои собственные, предназначенные сугубо для него команды, то необходимо добавить соответствующие команды в тип CommandID. После этого нужно расширить класс WavesClient для поддержки вашего вейвлета и для того, чтобы он обрабатывал и передавал новые команды вейвлету независимо от предка. И, в этом случае, заменить в GetClientViewServlet реализацию WavesClient на вашу собственную. И снова вуаля! (снова, не учитывая UI)

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

Javascript


  • ui.js занимается генерацией интерфейса, для каждого блока модели есть собственный метод
  • command.js отправляет и генерирует команды, принимает сообщения об обновлениях, а также содержит обработчики для кнопок
  • ajax.js скрипт, который давно пора заменить на соответствующий метод jquery, но никак не доходят руки :). используется в command.js

Для того, чтобы добавить генерацию вашей модели, достаточно добавить строку, вызывающую ваш метод обработки в методы CreateClient и renderUpdate объектаClientRenderer в ui.js и собственно написать этот метод. Всё остальное будет (должно) работать самостоятельно.

CSS


  • sametimed-plain.css ещё чуть более ужасный интерфейс чем цветной :)
  • sametimed-colored.css цветной, Windows 3.11-подобный интерфейс :).

Пока что стили, определяющие позиционирование и внешний вид (цветность) не разделены, хотя они разделяются комментариями в самих файлах. Думаю, я не буду этого менять.

Эпилог


Вышло много текста про один небольшой аппликейшн, но зато пост описывает все его возможности. Надеюсь найдётся не один человек, которому эта разработка будет интересна и если найдётся, планирую усовершенствовать его дальше. Пока это небольшая поделка «из интереса», но немного стараний — и её можно превратить в полноценный проект.

Тех, кто это будет тестировать, прошу постить баги в соответствующее место, в разумных пределах и не относящиеся к дизайну :).

Участие в разработке приветствуется но поощрить нечем, только лицензией :).

Важное пояснение


Если вы будете проверять приложение в работе одновременно с консольным клиентом wave-protocol, сообщения отосланные из консольного клиента будут приходить на одно позже. Это не баг и не фича, это способ генерации «документа» чата. В консольном случае Google, по крайней мере как посчитал я, изменили порядок записи элементов документа так, чтобы их было удобнее отображать в консоли (начало элемента, конец элемента, затем его содержимое). В моём случае элемент строится в привычном порядке (начало, содержимое, конец), этим и обусловлено это несоответствие. Если исправить порядок генерации в моём проекте на тот же, что и в консоли, они будут будут полностью друг другу соответствовать.

И да, специальной проверки/валидации введённых на клиенте данных пока не производится.

P.S. Собственно, абзац: Где-то с месяц назад в поисках работы я получил тестовое задание от некоторой фирмы X, аж на три недели. При том, что большую часть задания я выполнил и показал текущий на то время вариант в работе и прошёл 80% тестов на собеседовании, меня не приняли. Посему я считаю что имею право поделиться и исходным кодом и руководством к использованию с хабраобществом. Код я развил немного в другом направлении, но тем не менее он может оказаться полезным, даже если у гугла неожиданно окажется есть всё необходимое и в рабочем (доступном разработчикам) варианте.

да-да, слово editor используется часто применительно к проекту, потому что изначально он планировался (и планируется) как одновременный редактор

30 сентября 2009 г.

30 сентября

На сайте readwriteweb.com появилась информация о том, какие новости о Волне нас ждут 30 сентября (спасибо Алексею Исаченко за нахождение этой статьи).

Автор статьи побеседовал с командой Google Wave и сообщает такие подробности:
  • Google разошлет около 100 000 инвайтов.
    Их планируется примерно такое количество, но команда GW предполагает, что инвайтов в итоге может оказаться и больше. Все будет зависеть от успешности работ над стабильностью системы.
  • инвайты получат три группы пользователей: нынешние участники "песочницы", те пользователи, которые заполняли заявку на доступ к GW в течение нескольких последних месяцев (получат аккаунт в режиме "раньше пришел, раньше обслужили") и некоторое количество отобранных корпоративных (enterprise) пользователей с аккаунтами Google Apps.
  • дополнительные инвайты будут рассылаться по мере того, как команда GW будет увеличивать производительность Волны.
  • пользователи не смогут непосредственно рассылать инвайты друзьям, но каждый пользователь Волны сможет "номинировать" 8 своих друзей, которых переставят в начало очереди на получение новых аккаунтов.
  • все нынешние аккаунты будут перемещены из "песочницы" на домен wave.google.com.
    Новые фичи здесь, конечно, появятся в ближайшие месяцы, но по-прежнему главное внимание сейчас уделяется масштабированию системы. Не исключается появление креш-сообщений ("Все хорошо, прекрасная маркиза") и будут периодические отключения системы для обновления, как сейчас в девелоперской версии.
  • система управления контактами будет интегрирована с Google Contacts.
    Пока там будут показываться только пользователи, имеющие аккаунты в Google Wave.
  • команда Google Wave отберет некоторое количество роботов и виджетов, созданных разработчиками.
    Сейчас в Волне не будет AppStore или рынка роботов и виджетов. Пользователи смогут устанавливать себе лишь небольшое число отобранных командой GW приложений.
  • пользователям Internet Explorer будет выдаваться предупреждение о необходимости установить и использовать Chrome Frame.
    Вот об этом плагине по-русски на Хабре.
Еще о предстоящих изменениях можно прочитать в сообщении Ларса Расмуссена и Стефани Хеннон в официальном блоге Гугла и в сообщении Стефани Хеннон в блоге разработчиков Google Wave.

16 сентября 2009 г.

Начало регистрации заявок на участие в GDD 2009

На официальном блоге Google-Россия появилось сообщение о регистрации на GDD2009:
http://googlerussiablog.blogspot.com/2009/09/google-developer-day-200....
Перепечатываю его здесь.

Cайт GDD2009:
http://code.google.com/intl/ru/events/developerday/2009/home.html
Форма заявки:
https://dd2009.wegbox.com/ru

--

Объявляем о начале регистрации заявок на участие в Google Developer Day 2009 в Москве

16.09.2009



Спешим сообщить вам, что мы начинаем принимать заявки на участие в ежегодной конференции для веб-разработчиков "Google Developer Day", которая пройдёт 10 ноября в Москве. В прошлом году более 400 веб-разработчиков посетили эту конференцию, на которой они прослушали 12 выступлений и поучаствовали в 6 практических семинарах, посвящённых различным продуктам Google для веб-разработчиков. В этом году мы планируем подробно осветить Android, App Engine, Google Wave, Chrome, GWT, AJAX APIи многое другое.

На конференцию приедут наши команды инженеров, работающие над сервисами для веб-разработчиков и API, и вы сможете пообщаться с ними напрямую. Мы проведём несколько углублённых сессий с техническим уклоном, направленных на то, чтобы помочь разработчикам писать хорошие рабочие приложения на технологиях от Google и на открытых технологиях. Те, кто работает над созданием деловых приложений, тоже смогут найти себе что-то полезное в улучшенной и расширенной программе нашей конференции. И, конечно же, у разработчиков будет много возможностей познакомиться друг с другом и обсудить последние мобильные и веб-технологии во время "часов открытых дверей" и неформального общения по завершении конференции.

Мы прилагаем все усилия к тому, чтобы конференция была насыщенной, полезной и интересной! Чтобы узнать о конференции побольше и подать заявку на участие, заходите на сайт конференции.

Ждём вас на Google Developer Day!

17 августа 2009 г.

GUI для Волны



В одной из статей я описывал инсталляцию волнового демо-сервера FedOne. В «комплекте» к серверу имеется и клиент, с весьма примитивным текстовым интерфейсом. Я уверен, что у многих из тех, кто тестировал FedOne, возникала мысль о написании GUI-клиента к нему.

И вот Thomas Beverley выложил исходные тексты клиента FedOne с графическим пользовательским интерфейсом. На скриншоте вы можете посмотреть, как это все выглядит под Windows XP. Запущены сервер и два клиента.
Есть кнопки для практически всех команд, которые сейчас имеются в API (заготовлена даже пустая кнопка «Test butt», видимо, на будущее). В центре вы видите модальное окно для добавления нового участника в волну. Аналогичное окно появляется при удалении участника.

Процедура установки этой версии клиента проста. Нужно скачать исходные тексты и заменить ими папку\src\org\waveprotocol\wave\examples\fedone\waveclient\console. После этого запускаете «ant clean» (спасибо D.Unkovsky за напоминание :) и затем «ant» для перекомпиляции.
Как пишет автор, можно легко изменить клиент с помощью имеющегося класса WaveConnector.java. Этот класс полностью документирован и позволяет упростить взаимодействие с Google-волной. Базируясь на нем, вы можете построить свой собственный текстовый клиент или создать ваш вариант графического интерфейса. Как пример смотрите класс ConsoleClient.java.


P.S. И напоследок — небольшой трюк (Windows only), теперь уже от меня.
Раз уж мы говорим о графическом интерфейсе, давайте сделаем более удобным управление сервером и клиентами. Сейчас приходится запускать их с помощью bat-файлов, причем окна с запущенными процессами невозможно свернуть в трей.
Но мы можем воспользоваться удобной утилиткой LNK file improver by Dmitry Koteroff (dk@dklab.ru) из комплекта Denwer. Она позволяет запускать любую программу и сворачивать ее окно в трей. Если вы заглянете в текст этой маленькой (6656 байт) софтинки каким-нибудь редактором, то увидите, что прямо в исходном тексте можно отредактировать ее параметры: стартовый каталог, строку запуска с аргументами, адрес иконки, нужно ли запускать свернутой в трей, позволять ли запуск нескольких экземпляров и делать ли доступным пункт «Terminate» в контекстном меню (по правой кнопке) этой крохотули.
Единственно, что надо соблюдать при изменении текста — делать замену знаков, а не вставку.
Я сделал себе три разновидности этого исполняемого файла (сервер и два клиента), добавил иконку от Google Wave и теперь у меня на экране не висит несколько DOS-образных окон, а есть лишь пара-тройка волновых «змеек» в трее (их видно в правом нижнем углу скриншота).

11 августа 2009 г.

Меняем меню: расширения волнового клиента


Как известно, в Google Wave можно использовать два типа расширений (extensions) - гаджеты и роботы. Напомню:

Гаджет - небольшая программка, которая выполняется на стороне клиента, принадлежит определенной волне и позволяет ее участникам взаимодействовать между собой, поскольку они все могут менять статус гаджета и одновременно видят эти изменения. Наглядный пример - гаджет голосования. Вы проголосовали "за" или "против", гаджет учел ваш голос и изменил таблицу результатов. Все участники волны, в которую внедрен данный гаджет, увидели это изменение.
Робот - исполняется на стороне сервера. Можно даже сказать "на стороне серверов", поскольку сейчас роботы размещаются "в облаках", на серверах Google AppEngine. Робот - равноправный участник волны. Так же, как люди, он имеет доступ к содержанию волны, может его изменять, добавлять или удалять участников данной волны, а также создавать новые "блипы" (реплики в обсуждении) и новые волны.

Возникает вопрос, а как добавлять роботов или гаджеты в волну? Поскольку роботы - это полноценные участники волны, то их можно добавлять точно так же, как и людей. Заносите адрес робота в свою адресную книгу, а потом оттуда по мере необходимости подключаете робота к нужной волне. Гаджет вставляется с помощью специального пункта в меню "Debug" (мы сейчас говорим о волновом клиенте, который используется в "песочнице" Google Wave Sandbox - http://wavesandbox.com/).

Однако со временем понимаешь, что этот процесс нужно сделать более гибким. Часто приходится подключать сразу несколько роботов к волне. Или нужно вставить какой-то собственный гаджет, которого нет в общедоступной библиотеке (или, как правильно, "гаджетнице"? :). Для решения этих вопросов мы имеем в данное время простой механизм расширения интерфейса волнового клиента. С его помощью мы можем добавлять дополнительные кнопки в меню редактирования блипа и в меню создания новой волны. Вот как это выглядит.

Задача 1. Вы написали (или откопали где-то код) удобный гаджет. Часто и с удовольствием вставляете его в волну. Но вам не хочется постоянно лезть в меню "Debug" и добавлять строку с адресом гаджета. Хорошо бы иметь просто кнопку, которая будет вставлять нужный гаджет по мановению вашего пальца.

Создаете "манифест", т.е. XML-файл с таким примерно текстом:
<extension location="Toolbar">
<info text="Are You In?"
description="Click to insert the Are You In? gadget."
imageUrl="http://wave-api.appspot.com/public/gadgets/areyouin/icon.png"/>
<insertGadget url="http://wave-api.appspot.com/public/gadgets/areyouin/gadget.xml"/>
</extension>

Затем создаете новую волну, идете в меню "Debug >Add Extension Installer" и там указываете адрес, где лежит ваш "манифест".

Сохраняете волну (кнопка "Done"). В ней появляется изображение элемента из "пазлов" с названием вашего гаджета, надписью "Автор неизвестен" и кнопкой "Install". Ее и нажимаем.


Все, теперь в вашем меню редактирования "блипа" появляется новая кнопка, которая вставляет ваш гаджет куда пожелаете. (Гусары, молчать! :) На моем скриншоте вы видите добавленную кнопку с сине-белым логотипом facebook'а.


Примечание: Структура "манифеста", как видим, очень проста. Location указывает место, куда будет добавлена кнопка (сейчас допустимо два варианта - Toolbar и NewWaveMenu, о котором чуть ниже). Info text - пояснение. Description - более подробное описание гаджета. ImageUrl - расположение картинки для кнопки. InsertGadget url - соответственно, местоположение xml-файла вашего гаджета. Можете попробовать с демо-гаджетом, который лежит здесь - http://wave-api-dmo.appspot.com/public/simplemap/whereareyou.xml


Задача 2. Вы продались роботам, частенько выкрикиваете во сне "Слава роботам! Смерть человекам!" и в любую волну добавляете с десяток любимых ботов. Правильно, Твитти нужна? Нужна, кто ж сообщит последние сплетни из твиттера. Рози нужна? Нужна, кто ж будет переводить их с разных языков. "Иветта, Мюзетта, Жанетта..."

Хочется иметь возможность одним нажатием добавлять нужный гарем роботов (ну, и людей заодно, конечно) к волне.


Создаем другой манифест:
<extension location="NewWaveMenu">
<info text="New Twave"
description="Creates a new Twitter wave."/>
<createNewWave>
<participant id="tweety-wave@appspot.com"></participant>
</createNewWave>
</extension>

Точно так же открываем новую волну, затем идем в меню "Debug >Add Extension Installer" и там указываем адрес, где в сети лежит этот "манифест".
Оп! И в панели рядом с кнопкой "New Wave" появляется кнопка со стрелкой вниз, которая при нажатии на нее показывает выпадающее меню с добавленными вами пунктами.

Примечание: Как видим, тут изменилась Location, а также появилась возможность создавать волну (createNewWave) и добавлять в нее участников (participant).

Пока, насколько мне известно, еще нет способа таким же образом добавлять участников в существующую волну или удалять их оттуда. Но API будет со временем расширяться и улучшаться. И если эти ожидания сбудутся, то у нас с вами появится возможность подстраивать свою рабочую среду в волнах сообразно нашим персональным вкусам и предпочтениям.
Или создавать "клоны" волнового клиента, заточенные под определенный круг задач (IM, совместное редактирование текстов, дискуссионное или игровое сообщество и т.п.).
Или под умения и привычки пользователей (хм, "1С-волна" для бухгалтерии, это наверное было бы круто, да! :).