|
04-08-2008 Технология OSGi позволяет создавать модульные приложения, которое легко может конфигурироваться путем добавления,удаления или обновления модулей. В данном примеры мы рассмотрим создания простейшего веб-приложения как часть (модуль) другого приложения, основанного на OSGi
Simple Web-application on OSGi. Технология OSGi позволяет создавать модульные приложения, которое легко может конфигурироваться путем добавления,удаления или обновления модулей. В данном примеры мы рассмотрим создания простейшего веб-приложения как часть (модуль) другого приложения, основанного на OSGi.
В моем примере будут использоваться Tomcat 5.5, Spring MVC, Apache DBCP и в качестве реализации OSGi выбран Equanox, база данных PostgreSQL. Для начала необходимо скачать дистрибутивы вышесказанных библиотек, но в в виде osgi-модулей или бандлов и сам equnox (http://www.eclipse.org/equinox/). Обычные дистрибутивы библиотек отличаются от osgi-модулей лишь тем что в сборке последних хранится файл manifest.mf в котором заданы какие пакеты классов необходимы для работы данного модуля и какие пакеты классов модуль экспортирует в приложение, то есть какие пакеты могут использовать другие модули в этом приложении. Кроме этой информации в файле манифеста есть еще много настроек, но пока они нам не нужны. Вот весь список бандлов, используемых в моем примере: catalina.osgi.jar catalina.start.osgi.jar com.springsource.junit.jar com.springsource.net.sf.cglib.jar com.springsource.org.aopalliance.jar com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar com.springsource.org.apache.commons.pool-1.4.0.jar com.springsource.org.objectweb.asm.jar com.springsource.org.postgresql.jdbc3-8.3.603.jar com.springsource.slf4j.api.jar com.springsource.slf4j.log4j.jar com.springsource.slf4j.org.apache.commons.logging.jar commons-el.osgi.jar easymock.jar jasper.osgi.jar jsp-api.osgi.jar jstl.osgi.jar log4j.configuration-1.1.0.jar log4j.osgi.jar mx4j.osgi.jar org.eclipse.osgi.jar servlet-api.osgi.jar spring-aop.jar spring-beans.jar spring-context.jar spring-context-support.jar spring-core.jar spring-osgi-core.jar spring-osgi-extender.jar spring-osgi-io.jar spring-osgi-test.jar spring-osgi-web.jar spring-osgi-web-extender.jar spring-test.jar spring-web.jar spring-webmvc.jar
Самые основные это catalina.osgi.jar – содержит классы Tomcat, catalina.start.osgi.jar – используя классы из catalina.osgi.jar запускает Tomcat во время своей загрузки. То есть этот модуль содержит BundleActivator , который вызывается при старте бандла. Идем дальше, com.springsource.org.postgresql.jdbc3-8.3.603.jar – это драйвер базы данных PostgreSQL, com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar - Apache Connection Pool. Дальше стоит выделить бандл spring-osgi-web-extender.jar, он занимается тем что следит является ли бандл веб-приложением, тоесть war-ником, и если да и при условии что уже запущен веб-контейнер, в нашем случае Tomcat, то он разворачивает (деплоит) данное веб-приложение. Все остальные бандлы необходимы для работы вышеперечисленных. Бандлы можно скачать либо в репозитории Spring: http://www.springsource.com/repository/app/ либо в репозиторях Maven: http://www.mavenreposearch.com/. Итак, можно приступать к запуску. В папке где лежит equinox создаем папку configuration, в ней файл config.ini с примернол таким содержанием: eclipse.ignoreApp=true osgi.noShutdown=true osgi.console= osgi.clean=true osgi.bundles=com.springsource.slf4j.api.jar@start ….
Особо не вдаваясь в первые 4 строчки, стоит обратить вримания на последнюю. Она содержит бандлы , которые добавляются в систему. Бандлы подключаются в формате путь(относительно той директории где лежит equanox)@start, если бандл не нужно активировать то указываем просто путь к дистрибутиву. Запускаем Equanox : java -jar libs4/org.eclipse.osgi.jar. Дальше можно посмотреть статус всех бандлов с помощью команды ss. Если все хорошо то статус Active, если не найдены зависимости, то статус Installed, и если бандл неактивен то статус Resolved. Если при запуске бандла не реализована какая-либо зависимость, то в папке configuration создается лог-запись, по которой можно узнать в чем проблема. Создаем свой первый бандл, который содержит лиш интерфейс. Дальше можно посмотреть статус всех бандлов с помощью команды ss. Если все хорошо то статус Active, если не найдены зависимости, то статус Installed, и если бандл неактивен то статус Resolved. Если при запуске бандла не реализована какая-либо зависимость, то в папке configuration создается лог-запись, по которой можно узнать в чем проблема. Создаем свой первый бандл, который содержит лиш интерфейс. **
* */ package org.osminog.service; **
* @author Alexander Galibey * */ public interface MessageService { String getMessage();
}
И соответсвенно файл манифеста: Bundle-Version: 1.0 Bundle-SymbolicName: org.osminog.service Bundle-Name: Service Interfaces Bundle-Vendor: OSMinog group Export-Package: org.osminog.service Bundle-ManifestVersion: 1
Обратите внимание на строку,выделенную жирным шрифтом, она означает что пакет org.osminog.service другим модулям в системе. Дальше создаем другой бандл, который будет использовать этот пакет. **
* */ package org.osminog.service.impl; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.Statement; import javax.sql.DataSource;
import org.osminog.service.MessageService;
**
* @author Alexander Galibey * */ public class MessageServiceImpl implements MessageService { private DataSource dataSource; public DataSource getDataSource() {
return dataSource; } public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource; } public String getMessage() { String message = null; try{ Connection con = dataSource.getConnection(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select hello world! as text"); if (rs.next()){ message = rs.getString(1); } }catch (Exception e){ e.printStackTrace(); } return message; } }
Манифест: Bundle-Version: 1.0
Bundle-SymbolicName: org.osminog.serviceImpl Bundle-Name: Service Implementation Bundle-Vendor: OSMinog group Bundle-ManifestVersion: 2 Import-Package: org.osminog.service,javax.sql,org.postgresql;version="[8.3.603,8.3.603]",org.apache.commons.dbcp;version="[1.2.2.osgi,1.2.2.osgi]".
Этот модуль импортирует пакет с нашим интерфейсов, а также пакет драйвера базы данных и библиотеки Apache DBCP. Также в этом модуле используется Spring Context. Для этого в папке META-INFSpring созданы два файла: messageService.xml - обычный спринговый контекст: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="messageService" class="org.osminog.service.impl.MessageServiceImpl" >
<property name="dataSource"> <ref bean="dataSource" /> </property> </bean> <bean id="dataSource" class="org.osminog.service.impl.SimpleDataSource"> <property name="driverClassName"> <value>org.postgresql.Driver</value> </property> <property name="url"> <value>jdbc:postgresql:postgres</value> </property> <property name="username"> <value>postgres</value> </property> <property name="password"> <value>12345</value> </property> </bean> </beans>
И messageService-osgi.xml для обьявления сервисов: <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:service id="messageServiceOsgi" ref="messageService" interface="org.osminog.service.MessageService" /> </beans>
Мы имеем два модуля, первый экспортирует интерфейс, второй модуль создает его реализацию и создает сервис, который будет использовать наш третий модуль, являющийся веб-приложением. Третий модуль состоит из одного контроллера: **
* */ package org.osminog.web; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.osminog.service.MessageService;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; **
* @author Alexander Galibey * */ public class MessageController extends AbstractController { **
* */ private static final long serialVersionUID = 1L; private MessageService messageService;
public MessageController() {
} public MessageService getMessageService() {
return messageService; } public void setMessageService(MessageService messageService) {
this.messageService = messageService; } protected ModelAndView handleRequestInternal(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception { ModelAndView mav = new ModelAndView("echo.jsp");
mav.addObject("message", messageService.getMessage()); return mav; } }
Контекста, который находит обьявленный ранее сервис, и назначает его нашему контролллеру. <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <bean
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"> </bean> <bean id="messageController"
class="org.osminog.web.MessageController"> <property name="messageService" ref="messageService"> </property> </bean> <osgi:reference id="messageService" interface="org.osminog.service.MessageService"/>
</beans>
В web.xml мы подключаем контекс-класс OsgiBundleXmlWebApplicationContext: <?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <display-name>Simple OSMinog WebApp Bundle</display-name>
<description>Simple OSMinog War</description> <welcome-file-list>
<welcome-file>index.html</welcome-file> </welcome-file-list> <servlet>
<servlet-name>osminog</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>2</load-on-startup> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext </param-value> </init-param> </servlet> <servlet-mapping>
<servlet-name>osminog</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
В файле манифеста мы импортируем все библиотеки, необходимые для работы: Web-ContextPath: WebModule
Bundle-ManifestVersion: 2 Bundle-Name: Simple OSMinog War Bundle-SymbolicName: org.osminog.web Bundle-Classpath: .,/WEB-INF/classes Import-Package: javax.servlet;version="2.4.0", javax.servlet.http;version="2.4.0", javax.servlet.resources;version="2.4.0", javax.servlet.jsp;version="2.0.0", javax.servlet.jsp.jstl.core;version="1.1.2", javax.servlet.jsp.jstl.fmt;version="1.1.2", javax.servlet.jsp.jstl.tlv;version="1.1.2", org.apache.taglibs.standard.resources;version="1.1.2", org.apache.taglibs.standard.tag.common.core;version="1.1.2", org.apache.taglibs.standard.tag.rt.core;version="1.1.2", org.apache.taglibs.standard.tei;version="1.1.2", org.apache.taglibs.standard.tlv;version="1.1.2", org.osminog.service, org.springframework.web.servlet;version="[2.5.5,2.5.5.A]", org.springframework.osgi.web.context.support;version="[1.1.0,1.1.0]", org.springframework.web.servlet.mvc.support;version="[2.5.5,2.5.5.A]", org.springframework.web.servlet.mvc;version="[2.5.5,2.5.5.A]", org.springframework.web;version="[2.5.5,2.5.5.A]", org.springframework.web.servlet.view;version="[2.5.5,2.5.5.A]"
Версия манифеста должна быть 2, чтоб экстендер понял что это веб-приложение, и classpath необходимо задать. В echo.jps просто выводим полученную строку: <?xml version="1.0" encoding="utf-8" ?>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <html>
<body> Message: ${message} </body> </html>
В конечном итоге должны получить Message: hello world!.
Автор: Alexander Galibey
|