Реальный пиарJavaScriptПишем на JavaScript → SessionMan решает проблему сохранения состояний в вебсервисах

SessionMan решает проблему сохранения состояний в вебсервисах

Обзор
Вебсервисы уже давно стали настолько популярными, что их поддержка вошла в Java SE 6. Сейчас уже трудно удивить кого-то гетерогенной архитектурой приложения, в которой серверная часть реализована на Java, а клиентская на .Net или наоборот. Веб сервисы обладают огромным списком преимуществ и не меньшим списком недостатков, устранение одного из которых и является целью данной статьи.
Проблема
Варианты решения проблемы для Axis2
WSDL — каркас любого вебсервиса
SessionMan выходит на арену
LogOut и "чистка" сессий
Заключительное слово
Ресурсы
Проблема

"By design, Web services are said to be stateless..." — эта фраза говорит о многом! Это значит, что используя веб сервисы, не составит труда передать на сервер код города и в ответ получить прогноз погоды на неделю. Но, для того чтобы организовать систему клиент-банк с использование Axis2*, придется потрудиться т.к. такая система предполагает процедуру авторизации и поддержку сессии в течении некоторого периода времени.
Замечание
* Axis2 — второе поколение наиболее популярного движка для веб сервисов, разрабатываемого под эгидой Apache Software Foundation.
Варианты решения проблемы для Axis2

Мои поиски решения этой проблемы привели к одной статье [1], в которой ребята из IBM предлагают свое решение. Его смысл сводится к тому, что в сервис-класс, сгенерированный Axis2 добавляется статическое поле (HashMap), который и является хранилищем информации о сессии пользователя, а wsdl сервиса преобразуется таким образом, что появляется две дополнительных операции login и logout.
Единственным недостатком или скорее ограничением в приведенном примере [1], является то, что клент должен явно выполнять операцию logout, в противном случае информация о сессии так и останется дожидаться перезагрузки сервера приложений, а HashMap станет источником утечки памяти и проблем в производительности.

Решением проблемы также может стать Open Source библиотека SessionMan, предоставляющая базовый набор функций для работы с сессиями в любом Java-приложении и выполняющая периодическую сборку мусора, состоящую в удалении устаревших сессий.

Для рассмотрения примера использования SessionMan, нам понадобятся TomCat и Axis2. Установите TomCat, Axis2 и проверьте их работоспособность, воспользовавшись документацией к каждому из продуктов и мы продолжим наше повествование.
WSDL — каркас любого вебсервиса

Мы начнем нашу работу с того, что создадим wsdl-документ, описывающий наш будущий вебсервис:
<portType name="SessionManExamplePort">
<operation name="login">
<input name="loginOpIn" message="tns:loginSoapMessage" />
<output name="loginOpOut" message="tns:sessionSoapMessage" />
</operation>
<operation name="disconnect">
<input name="disconnectOpIn" message="tns:sessionSoapMessage"/>
<output name="disconnectOpOut" message="tns:isOkSoapMessage" />
</operation>
<operation name="ping">
<input name="pingOpIn" message="tns:sessionSoapMessage" />
<output name="pingOpOut" message="tns:pingSoapMessage" />
</operation>
</portType>

Как видно из фрагмента wsdl — наш вебсервис будет содержать три операции: login, disconnect** и ping. Первая операция принимает SOAP конверт в который упакованы имя пользователя и его пароль:
Замечание
** имя метода выбрано не случайно, т.к. в одной из версий Axis2 v.1.0 были ошибки, и операция logout обрабатывалась некорректно.

<xsd:element name="UserAuthElement">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="login" type="xsd:string"
minOccurs="1" maxOccurs="1"/>
<xsd:element name="password" type="xsd:string"
minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

Оставшиеся же две принимают только SOAP конверт содержащий идентификатор сессии, что с одной стороны, необходимо для проверки актуальности сессии перед выполнением любой операции, и с другой — вполне достаточно для объяснения работы с библиотекой SessionMan.

После того, как wsdl-документ создан, мы запускаем утилиту wsdl2java, прилагающуюся к Axis2 и дожидаемся окончания генерации всех необходимых классов.

Полнофукнциональный пример, использующий библиотеку SessionMan, совместно с Axis2, доступен из SVN репозитория: http://sessionman.googlecode.com/svn/trunk/sessionman-example.

Инструкция по сборке проекта для работы в среде Eclipse 3.2: http://sessionman.googlecode.com/svn/trunk/sessionman-example/readme.txt.
SessionMan выходит на арену

Результатом работы wsdl2java является целый пакет классов, среди которых SessionManExampleServiceSkeleton — сердце нашего будущего сервиса. Для дальнейшей работы мы унаследуем этот класс и создадим свой SessionManExampleService.

Подключаем SessionMan:
import com.webtair.session.*;
import com.webtair.session.artifact.*;
import com.webtair.sessionman.ws.types.*;

Добавляем контроллер сессий к сервис классу:
public class SessionManExampleService extends
SessionManExampleServiceSkeleton {
...
/** SessionMan instance — main goal of this example */
private static SessionMan<SimpleSessionInfo> sessions
= new SessionMan<SimpleSessionInfo>();

Здесь необходимы пояснения:
Класс com.webtair.session.SessionMan имеет два конструктора: public SessionMan(ConfigBean config) и public SessionMan() — второй создает конфигурацию по умолчанию со временем жизни сессии 30мин и периодичностью очистки устаревших сессий 10мин. С помощью первого конструктора пользователю предоставляется возможность управлять этими параметрами, а так же определить стартовую размерность таблицы для сессий, передав, соответствующим образом настроенный, com.webtair.session.config.ConfigBean
В качестве хранилища вашей информации может использоваться любой класс, реализующий интерфейс com.webtair.session.artifact.SessionInfo, для базовых операций с сессией библиотека предоставляет класс SimpleSessionInfo.

Таким образом, если Вам необходимо создать хранилище для, скажем состояния корзины, достаточно будет реализовать интерфейс SessionInfo c сответствующей функциональностью.

Создаем сессию и возвращем ее кленту вебсервиса:
/**
* Method that allow for client to login under this ws
* @return IdSessionDocument — soap envelope with session id;
*/
@Override
public IdSessionDocument login
(UserAuthElementDocument userAuthElementDocument) {
/* default login and pass for examples only. At this place you
* mast recieve real pass from the real storage like RDBMS or
* config-file or somthing else.
*/
String defaultLogin = "sessionman";
String defaultpass = "example";

UserAuthElement userAuthElement =
userAuthElementDocument.getUserAuthElement();

if (userAuthElement.getLogin().equals(defaultLogin)
&& userAuthElement.getPassword().equals(defaultpass)){

// request for id session from SessionMan lib
idSession =
sessions.putSessionInfo(userAuthElement.getLogin(),
new SimpleSessionInfo());
}
...
}

Ключевым выражением в процедуре получения идентификатора является метод putSessionInfo(), "вкладывающий" в HashMap контроллера SessionInfo и возвращающий уникальный идентификатор сессии.

Провереям актуальность сессии:

Вызов метода validateSession(String idSession), позволяет не только проверить "жива" ли сессия, но и автоматически обновляет время ее последнего использования, что приводит к ее автоматическому пролонгированию на время указанное в ConfigBean (30 мин по умолчанию).

Вызов метода isSessionExpired(String idSession), позволяет просто определить завершилось ли время жизни сессии, не обновляя ее последнего использования.
LogOut и "чистка" сессий

Если пользователь не выполнил явной операции disconnect (logout), чисткой HashMap займется фоновый поток, который проснется через интервал времени, определенный в ConfigBean.
Заключительное слово

Полнофукнциональный пример, использующий библиотеку SessionMan, совместно с Axis2, доступен из SVN репозитория: http://sessionman.googlecode.com/svn/trunk/sessionman-example.


Источник: http://www.javaportal.ru

Рекомендуем



Введение в превалирование объектов Разработчик должен преобразовать объекты в таблицы баз данных, XML файлы, или использовать какой-нибудь другой не объектно-ориентированный способ представления данных, полностью нарушающий инкапсуляцию


Работаем с JAR-архивами Ну а теперь, имея список содержимого jar-архива, мы спокойно можем распаковывать его, не забывая создавать подкаталоги, содержащиеся в архиве


Проблемы реализации постраничной загрузки таблиц с помощью компонент Hibernate и Java Наиболее оптимальным компонентом является интерфейс ScrollableResults, который имеет все необходимые методы для перемещения по выборке, а использование класса DetachedCriteria, позволяет после выборки объектов закрыть сессию с СУБД