Наконец-то пришло время рассмотреть, как выполняется развертывание приложения, основанного на OSGi, в обычном, а не приспособленном специально для Equinox, сервлет-контейнере (или сервере приложений, в дальнейшем будем употреблять только термин "сервлет-контейнер"), таком как Tomcat, GlassFish, IBM WebSphere и т.д.
Постановка задачи
Приложение, предназначенное для работы в сервлет-контейнере, должно иметь стандартную структуру каталогов:
--\WEB-INF
-----\classes
-----\lib
-----web.xml
--\META-INF
-----MANIFEST.MF
Строго говоря, обязательным является лишь наличие каталога WEB-INF и дескриптора развертывания web.xml. Однако, большинство веб-приложений имеют в своем составе сервлеты и другие классы, которые помещаются в каталог classes или упаковываются в jar-архивы, которые помещаются в каталог lib.
Как известно у OSGi-приложения другая структура:
--\configuration
-----config.ini
--\features
-----\feature1
-----\feature2
-----\...
--\plugins
-----\plugin1
-----\plugin2
-----\...
Поэтому, чтобы развернуть OSGi-приложение в сервлет-контейнере, необходимо сделать следующее:
1. Скопировать структуру каталогов OSGi-приложения в каталог WEB-INF
2. Добавить в каталог WEB-INF дескриптор развертывания web.xml
3. В дескрипторе развертывания прописать перенаправление всех запросов (/*) на специальный сервлет, который будет обеспечивать вызов OSGi-сервиса HttpService, который, в свою очередь, будет перенаправлять запросы зарегистрированным сервлетам. Соответственно, этот сервлет должен присутствовать в каталоге WEB-INF.
4. В методе init сервлета, перенаправляющего запросы в OSGi-сервис HttpService, должна производиться инициализация OSGi-фреймворка.
Все вышеперечисленные задачи решаются с помощью такого механизма платформы Equinox, как Servletbridge.
Анатомия Equinox Servletbridge
Начиная с версии 1.2, которая вышла вместе с Equinox 3.6M3, состав и функциональность Servletbridge поменялась. Если раньше существовал антовский скрипт, который парсил набор фич, создавал нужную структуру каталогов и экспортировал бандлы, то теперь вся работа ведется через Eclipse PDE и механизм продуктов, подробно описанный в статье. Прежде всего нужно загрузить Servletbridge с CVS-сервера dev.eclipse.org. Для этого в визарде загрузки проекта из CVS необходимо использовать следующие настройки подключения:
Host: dev.eclipse.org
Repository path: /cvsroot/rt
User: anonymous
Connection type: pserver
После подключения в дереве проектов нужно открыть org.eclipse.equinox/server-side и выбрать следующие бандлы: org.eclipse.equinox.http.servletbridge, org.eclipse.equinox.servletbridge, org.eclipse.equinox.servletbridge.extensionbundle и фичи: org.eclipse.equinox.server.core и org.eclipse.equinox.server.servletbridge.
Фича org.eclipse.equinox.server.core является общей для всех фич, предоставляющих механизмы работы equinox в рамках сервлет-контейнера. Напомню, что фича (Feature) - это набор логически связанных бандлов, имеющих какие-то общие настройки брендинга, лицензию и т.д. В данном случае, фича org.eclipse.equinox.servlet.core содержит бандлы, предоставляющие платформу Equinox (org.eclipse.osgi, org.eclipse.osgi.services, org.eclipse.equinox.common), механизм декларативных сервисов org.eclipse.equinox.util, org.eclipse.equinox.ds) и механизм точек расширения (org.eclipse.equinox.registry, org.eclipse.equinox.http.registry).
Фича org.eclipse.equinox.server.servletbridge интересна тем, что содержит каталог rootfiles, в котором и находятся файлы, характерные для веб-приложения. При экспорте продукта, все файлы, находящиеся в каталогах rootfiles будут скопированы в корневой каталог экспорта (в нашем случае - каталог WEB-INF). В фиче org.eclipse.equinox.server.servletbridge находятся следующие файлы: дескриптор развертывания web.xml, конфигурация запуска OSGi - launch.ini, директория lib c файлом org.eclipse.equinox.servletbridge_1.2.0.vXXX.jar, в котором хранится сервлет-диспетчер и средства инициализации платформы.
Файл org.eclipse.equinox.servletbridge_1.2.0.vXXX.jar является экспортированным бандлом org.eclipse.equinox.servletbridge и при необходимости может быть заменен более свежей сборкой.
В дескрипторе развертывания web.xml определены следующие параметры метода init сервлета:
- commandline - описывает аргументы командной строки, которые будут переданны OSGi-фреймворку при старте. По-умолчанию данное значение выставлено в -console, поэтому при старте откроется OSGi-консоль. Можно указать -console порт, тогда консоль будет слушать определенный порт и к ней можно будет подключиться через telnet.
- enableFrameworkControls - логический параметр, принимающий значения true/false. Если значение установлено в true, то можно управлять OSGi-фреймворком обращаясь по урлам специального вида - начинающимся на sp_: http://yourhost/yourcontext/sp_command (например, http://localhost/bridge/sp_stop). Доступны следующие команды:
- sp_deploy - копирует содержимое платформы в каталог установки.
- sp_undeploy - удаляет копию Eclipse из каталога установки.
- sp_redeploy - перезапускает платформу, т.е. останавливает, удаляет, копирует заново и запускает.
- sp_start - запускает развернутую платформу.
- sp_stop - останавливает платформу.
- sp_test - проверяет, настроен ли делегат, которому будут перенаправляться запросы. Если все хорошо, будет возвращен следующий результат: Servlet delegate registered - org.eclipse.equinox.http.servlet.HttpServiceServlet. Это значит, что с платформой можно работать и регистрировать в ней сервлеты.
- sp_deploy - копирует содержимое платформы в каталог установки.
Развертывание приложения с помощью Servletbridge
Посмотрим, как осуществляется развертывание OSGi веб-приложения с помощью Servletbridge. Предположим, что у нас уже есть бандл name.samolisov.servlet.ds.demo, содержащий сервлет, регистрируемый с помощью декларативного сервиса и описанный в статье.
Внимание: к бандлу, в котором осуществляется регистрация сервлета, есть одно требование. Данный бандл не должен содержать javax.servlet в списке Required-Bundle. Вместо этого необходимо импортировать пакеты javax.servlet и javax.servlet.http в параметре Import-Package.
Теперь необходимо создать RCP-приложение. Т.к. в данном примере не требуется делать какие-либо глобальные инициализации, то приложение фактически является пустым и будет использоваться только для развертывания Servletbridge. Далее, следует создать файл определения продукта, назовем его servlet.demo.product. Прежде всего нужно создать новый продукт, нажав кнопку New в блоке Product Definition на вкладке Overview. В появившемся диалоговом окне выбираем наше приложение и задаем название продукта, например Servlet Product.
Т.к. мы создаем веб-приложение, то нам не нужны бинарные компоненты, такие как лаунчер и файл eclipse.exe, поэтому галочку The product includes native launcher artifacts нужно снять.
Поскольку Servletbridge представлен двумя фичами org.eclipse.equinox.server.servletbridge и org.eclipse.equinox.server.core, то необходимо будет создавать продукт, основанный на фичах, - установить значение параметра The product configuration is based on в значение features. Так же необходимо создать фичу, инкапсулирующую наш бандл name.samolisov.servlet.ds.demo.
Чтобы создать фичу, нужно выбрать в меню New... проект Plug-In Development/Feature project.
Появится визард Feature Project. На первой его странице указываем имя проекта, в данном примере - name.samolisov.servlet.demo. По-умолчанию идентификатор фичи совпадает с именем проекта. При желании можно поменять название фичи, версию и указать автора.
На второй странице визарда необходимо выбрать банды, из которых будет состоять фича. Выбираем единственный бандл name.samolisov.servlet.ds.demo и нажимаем кнопку Finish.
На вкладке Dependencies конфигуратора продукта указываем фичи, составляющие наше приложение и Servletbridge:
- name.samolisov.servlet.demo
- org.eclipse.equinox.server.core
- org.eclipse.equinox.server.servletbridge
На вкладке Configuration создаем конфигурацию запуска. Здесь необходимо указать бандлы, которые будут стартовать автоматически при запуске платформы. Это, прежде всего, бандл org.eclipse.equinox.ds, предоставляющий механизм декларативных сервисов, и бандл org.eclipse.equinox.http.servletbridge, регистрирующий делегата для сервлета-диспетчера.
После данных манипуляций продукт создан и его можно экспортировать. В визарде экспорта следует указать значение настройки Root directory: равное WEB-INF и снять галочку Generate metadata repository.
Теперь можно запускать сервлет-контейнер. Я пробовал Tomcat 5,6,7. После запуска проверим, зарегистрировался ли наш сервлет welcome. Для этого перейдем по адресу http://localhost:8080/bridge/welcome. Как видим, сервлет зарегистрирован и работает:
Т.к. в дескрипторе развертывания web.xml параметр commandline установлен в значение -console, то при старте приложения доступна OSGi-консоль. Можно посмотреть список зарегистрированных в фреймворке бандлов с помощью команды ss:
Для себя я выбрал следующую схему работы: тестировать и отлаживать веб-приложение на Jetty, входящем в поставку Equinox, используя соответствующую конфигурацию запуска, а затем деплоить на Tomcat с помощью ServletBridge. Т.к. я не использую возможности больших серверов приложений, то данная схема работы мне подходит. Здесь, кстати, тоже видно преимущество модульных архитектур: основное приложение максимально независимо от окружения, которое можно менять двумя щелчками мыши в визардах, не трогая исходного кода.
Исходники, файл продукта и файл описания целевой платформы доступны на GitHub
Понравилось сообщение - подпишитесь на блог или читайте меня в twitter
6 комментариев:
обратимся к первоисточнику http://eclipse.org/equinox/server/http_quickstart.php
... Embed a server in Equinox (recommended) Only when you go to production or in special circumstances will you need to embed Equinox in an existing servlet container.
Так вот, почему же в продакшне надо сувать equinox в сервлет-контейнер, не подскажете нубу?
.. а еще вон, что есть http://eclipse.org/virgo/ ... но Вы, наверняка, в курсе.. ;)
Блоггер сегодня тупит с комментариями. Поступил комментарий от анонимуса:
обратимся к первоисточнику http://eclipse.org/equinox/server/http_quickstart.php
... Embed a server in Equinox (recommended) Only when you go to production or in special circumstances will you need to embed Equinox in an existing servlet container.
Так вот, почему же в продакшне надо сувать equinox в сервлет-контейнер, не подскажете нубу?
.. а еще вон, что есть http://eclipse.org/virgo/ ... но Вы, наверняка, в курсе.. ;)
Обычно продакшн редко строят на Jetty, которая входит в состав Equinox. Считается, что Tomcat - более зрелый проект + позволяет на одной инсталяции запускать несколько приложений. К тому же иногда в компании уже куплен какой-нибудь большой Application Server и хочется запустить приложение на нем. Поэтому и был создан ServletBridge.
Про проект Virgo я в курсе, даже подписан на их список рассылки. Правда пощупать на решении какой-нибудь реальной задачи пока не было времени.
Здравствуйте.
Спасибо вам большое за ваш цикл статей об OSGI и Equinox. Это просто неоценимая помощь для меня.
Собственно у меня есть такая проблема и я был бы очень признателен за помощь.
Пользуюсь ServletBridge и очень часто требуется обновить главный бандл без заливки всего архива war на сервер. И была замечена такая особенность - не всегда получается корректно обносить бандл. Во первых бандл с предыдущей версией может намертво прописаться в моей платформе. Через uninstall удаляется временно, и при следующей перезагрузке tomcat-а опять начинает мозолить глаза. Во вторых - происходит утечка памяти при обновлении бандла. Лечится только перезагрузкой томката.
Возникали ли у вас такие проблемы? а то уже вообще складывается впечатление, что Equinox в сервлет-контейнере не предназначен для моей модели разработки и нужно перебираться на Virgo
"Т.к. я не использую возможности больших серверов приложений, то данная схема работы мне подходит."
А почему не используете?
Статья написана в 2010-м году. Тогда не использовал, последние 4 года только с ними и работаю: WebLogic (есть несколько сертификатов), теперь WebSphere (WebSphere на мейнфреймах, работаю в IBM).
Отправить комментарий
Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!