Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Распределенные сервис-ориентированные системы..pdf
Скачиваний:
16
Добавлен:
05.02.2023
Размер:
9.2 Mб
Скачать

3.1 Учебная инфраструктура темы

Современные технологии доступа к данным основаны на общей парадигме слабосвязанных систем и максимальном управлении взаимодействием с СУБД с помощью сервиса контейнеров платформы Java EE.

В терминах данной дисциплины, бизнес-приложение — это EJB/EJBLight компонент, управляемых собственным контейнером. Поэтому технологию JPA проще демонстрировать на конкретном простом компоненте EJB-Light, что и делается в данном подразделе.

Соотвественно, рассматриваемая компонента должна быть помещена в в контейнер сервера приложений Apache TomEE, а в самом контейнере должна быть указана СУБД, обслуживаемая контейнером.

Простейшая задача, которую можно интерпретировать различными прикладными вариациями, — хранение в базе данных СУБД списка текстовых сообщений пользователей, которые можно добавлять, модифицировать и удалять. Доступ к этому списку сообщений осуществляется через Web-контейнер сервера приложений.

Конкретизируем поставленную задачу в следующих двух пунктах.

3.1.1 Учебная задача Letters (Письма)

Для последущего проектирования и реализации, учебная задача конкретизируется следующим образом.

На сервере приложений учебная задача обслуживается EJB-компонен- том с именем Letters, который манипулирует объектами класса Letter.class и предоставляет сессионным компонентам пользователей следующие функции:

а) getList() — получить список всех объектов класса Letter, хранящихся в базе данных;

б) getLetter(int id) — получает объект класса Letter по значению его идентификатора id;

в) addLetter(Letter letter) — добавляет объект класса Letter в базу данных; г) deleteLetter(int id) — удаляет объект из базы данных;

д) modLetter(Letter letter) — модифицирует объект в базе данных.

Объект манипулирования — класс Letter имеет слудующие атрибуты (поля данных):

а) id — уникальный идентификатор объекта;

б) date — дата и время создания или последней модификации;

128

в) user — имя авторизованного пользователя, создавшего или модифицировавшего запись;

г) text — текстовое сообщение объемом не более 4 КБайт.

Имеющейся информации вполне достаточно для демонстрации учебного материала изучаемой темы.

Будет большой ошибкой наделять компоненту Letters множеством разнообразных функций. Это неминуемо приведет к ее усложнению.

Правильный подход — множить функциональность на уровне сессий пользователей, а лучше — на уровне запросов к серверу приложений.

3.1.2 Корпоратиные EJB-компоненты

EJB-компоненты — это серверные компоненты, которые инкапсулируют в себе бизнесприложения, обеспечивают взаимодействие с базами данных, заботятся о транзакциях и безопасности.

Сприкладной точки зрения компоненты бывают разные. В данной главе нас интересуют EJB-компоненты, взаимодействующие с СУБД и проводящие манипуляции по сохранению данных.

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

Спозиции разработчика приложений выделяется всего три типа EJBкомпонент: без сохранения состояния, с сохранением состояния и одиночные.

@Stateless-компонента — EJB-компонента без сохранения состояния.

Она применяется, когда решение задачи можно осуществить одним вызовом метода.

@Statefull-компонента — EJB-компонента с сохранением состояния. Она поддерживает диалоговое состояние, которое может сохраняться между вызовами методов в пределах одной сессии, поэтому полезна для решения задач, с которыми нужно справляться за несколько этапов (обращений к серверу).

@Singleton-компонента — одиночная EJB-компонента. Она совместно используется всеми клиентами и поддерживает конкурентный доступ. Контейнер сам заботится о том, чтобы для всего приложения имелся только один экземпляр.

EJB-компонента — это обычный JAVA-класс, удовлетворяющий следующим ограничениям:

129

1)класс должен быть снабжен одной из указанных выше аннотаций или XML-эквивалентом в дескрипторе развертывания;

2)должен реализовывать методы своих интерфейсов, если они имеются;

3)класс должен быть определен как public и не может быть определен как final или abstract;

4)класс должен иметь конструктор public без аргументов, который кон-тей- нер будет использовать для создания экземпляров;

5)класс не должен определять метод finalize();

6)имена методов класса не должны начинаться с ejb и они не могут быть final или static;

7)аргумент и возвращаемое значение удаленного метода должны относиться к допустимым типам RMI.

Бизнес-интерфейс — это стандартный Java-интерфейс, который не расширяет никаких EJB-специфичных интерфейсов.

Распределенные системы — это мир интерфейсов, что наглядно демонстрирует рисунок 3.1.

Рисунок 3.1 — Сессионные EJB-компоненты для клиентов разных типов [17]

Сессионный EJB-компонент — это управляемый объект сервера приложений, обслуживающий сессию клиента (приложения клиента) посредством локальных или удаленных вызовов. Сама возможность обслуживания клиентов определяется интерфейсами, которые реализуют и предоставляют EJB-компо- ненты.

В целом, интерфейсы подразделяются на локальные и удаленные, что обозначается соответствующими аннотациями:

130

а) @Local — обозначает локальный бизнес-интерфейс. Параметры методов передаются по ссылке от клиента к EJB-компоненту;

б) @Remote — обозначает удаленный бизнес-интерфейс. Параметры методов передаются по значению и нуждаются в том, чтобы быть сериализуемыми как часть протокола RMI.

Проведем демонстрацию сказанного формальным описанием учебной задачи Letters, предполагая, что все указанные представления проводятся в учебном проекте lab4 типа Dynamic Web Project.

Сначала необходимо дать описание класса Letter, которое реализуем в виде сериализованного POJO-класса, представленного на листинге 3.1.

Листинг 3.1 — Исходный текст класса Letter.java проекта lab4

package rsos.lab4;

import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date;

public class Letter implements Serializable

{

// Идентификатор сериализации

private static final long serialVersionUID = 1L;

private int id; private Date date; private String user; private String text;

// Конструкторы public Letter() {

}

public Letter(Date date, String user, String text) { this.date = date;

this.user = user; this.text = text;

}

// Геттеры и сеттеры POJO-класса public int getId() { return id; }

public void setId(int id) { this.id = id;

}

public Date getDate() { return date; }

public void setDate(Date date) { this.date = date;

}

131

public String getUser() { return user; }

public void setUser(String user) { this.user = user;

}

public String getText() { return text; }

public void setText(String text) { this.text = text;

}

// Дополнительные функции форматирования public String toString() {

return Integer.toString(id) + " " + date.toString() + " " + user + " " + text;

}

public String getDateString() { SimpleDateFormat sdf =

new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); return sdf.format(date);

}

}

Теперь, на основе методов класса Letters, создим два интерфейса, например, LocalLetter и RemoteLetter, представленные на листингах 3.2 и 3.3.

Листинг 3.2 — Исходный текст интерфейса LocalLetter.java проекта lab4

package rsos.lab4;

import java.util.List; import javax.ejb.Local;

@Local

public interface LocalLetter

{

//Получить список писем List<Letter> getList();

//Получить письмо по идентификатору Letter getLetter(int id);

//Добавить письмо

void addLetter(Letter letter);

//Удалить письмо по идентификатору void deleteLetter(int id);

//Модифицировать письмо

void modLetter(Letter letter);

}

132

Локальный интерфейс объявляет все пять заявленных ранее методов, что обычно справедливо для локальных взаимодействий.

Листинг 3.3 — Исходный текст интерфейса RemoteLetter.java проекта lab4

package rsos.lab4;

import java.util.List; import javax.ejb.Remote;

@Remote

public interface RemoteLetter

{

//Получить список писем List<Letter> getList();

//Получить письмо по идентификатору Letter getLetter(int id);

//Добавить письмо

void addLetter(Letter letter);

//Удалить письмо по идентификатору void deleteLetter(int id);

//Модифицировать письмо

void modLetter(Letter letter);

}

Представленный на листинге 3.3 удаленный интерфейс с точностью до аннотации повторяет локальный интерфейс. В общем случае — это не так, потому что обычно удаленный интерфейс запрещает какие-либо методы или называет их по другому. Возможно добавляются дополнительные методы, например, обеспечивающие авторизацию доступа и другие.

EJB-компонент обеспечивает интерфейс тогда, когда он его реализует. Так, на листинге 3.4 представлена заготовка Letters «без сохранения состояния», обеспечивающая представление интерфейсов LocalLetter и RemoteLetter.

Листинг 3.4 — Заготовка исходного текста класса Letters.java проекта lab4

package rsos.lab4;

import java.util.Date; import java.util.List; import javax.ejb.Stateless;

@Stateless

public class Letters implements LocalLetter, RemoteLetter

{

public List<Letter> getList() {return null;}

133

public Letter getLetter(int id) {

Letter letter = new Letter(new Date(), "upk", "Сообщение"); letter.setId(id);

return letter;

}

public void addLetter(Letter letter) {}

public void deleteLetter(int id) {}

public void modLetter(Letter letter) {}

}

EJB-компонент без обеспечения интерфейса, даже если он реализует интерфейс, должен помечаться аннотацией @LocalBean.

В общем случае не обязательно помечать интерфейсы аннотациями. Это можно сделать при описании EJB-компонента. Например, можно потребовать, чтобы класс Letters не обеспечивал интерфейсы, тогда начало листинга 3.4 можно заменить на содержание, показанное на листинге 3.5.

Листинг 3.5 — Измененное начало класса Letters.java проекта lab4

package rsos.lab4;

import java.util.List; import javax.ejb.Local; import javax.ejb.LocalBean; import javax.ejb.Remote; import javax.ejb.Stateless;

@Stateless @Local(LocalLetter.class) @Remote(RemoteLetter.class) @LocalBean

public class Letters implements LocalLetter, RemoteLetter

{... }

EJB-компоненты «без сохранения состояния» также могут вызываться удаленно как Webслужбы SOAP, используя аннотацию @WebService, или как RESTful, используя аннотацию

@Path.

Указанным Web-службам посвящены главы 5 и 6 данного учебного пособия, а сейчас проверим работоспособность EJB-компонента Letters.

Для ссылок на сессионные EJB-компоненты предназначена аннотация EJB (javax.ejb.EJB).

В общем случае, внедрение зависимостей возможно только в управляе-

134

мых средах вроде EJB-контейнеров, Web-контейнеров и контейнеров клиентских приложений. Для нас важно, что внедрение EJB-компонентов можно выполнить в классе порожденном от HttpServlet. Для проверки данного факта создадим в проекте lab4 новый сервлет с именем JpaServlet и включим в него EJB-компоненты, показанные на листинге 3.6.

Листинг 3.6 — Тестовый вариант сервлета JpaServlet.java проекта lab4

package rsos.lab4;

import java.io.IOException; import java.io.PrintWriter; import javax.ejb.EJB;

import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

/**

* Servlet implementation class JpaServlet */

@WebServlet("/JpaServlet")

public class JpaServlet extends HttpServlet

{

private static final long serialVersionUID = 1L;

@EJB

 

 

private LocalLetter

local;

// Интерфейс

@EJB

 

 

private RemoteLetter

remote;

// Интерфейс

@EJB

 

 

private Letters

letters;

// EJB-компонент

/** * Конструктор */

public JpaServlet() { super(); }

/**

* Метод doGet(...) */

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException

{

response.setCharacterEncoding("UTF-8"); response.setContentType("text/plain"); PrintWriter out = response.getWriter();

out.println("local =[" +

local.getLetter(1)

+ "]");

out.println("remote =[" +

remote.getLetter(2)

+

"]");

out.println("letters=[" +

letters.getLetter(3)

+

"]");

135