Обзор примера
Материал этой лекции будет излагаться на примере - упрощенном фрагменте телекоммуникационной системы из области мобильной телефонии. Данная система реализует стык пользовательского интерфейса мобильного телефона (клавиатурный ввод и дисплейная индикация) и верхнего уровня интерфейса телефона с наземной сетью.
Эта система, без сомнения, является реактивной. Она асинхронно взаимодействует с пользователем телефона и сетью. Она прерываема - например, обязана обслуживать экстренные вызовы (связь с МЧС), находясь практически в любых состояниях. Работа системы ограничена строго заданными временными интервалами (это, к сожалению, в примере будет затронуто лишь слегка, иначе он получился бы слишком сложным). Система работает по различным сценариям, имея, кроме главного, "хорошего" сценария, множество "боковых веток"1). Наконец, архитектура системы организована в виде параллельно работающих компонент.
Этим примером хотелось продемонстрировать, что в случае реактивных систем целесообразно создавать UML-спецификации с последующей автоматической генерацией конечного кода приложения. Как уже отмечалось выше, генерация целевого кода по UML-диаграммам желательна, но часто наталкивается на препятствия. Таким препятствием является отсутствие емких визуальных абстракций - одновременно и наглядных, и имеющих полноценную исполняемую семантику, достаточную для эффективной генерации целевого программного кода.
Успешными средствами моделирования реактивных систем являются диаграммы композитных структур (вариант для компонент) в связке с диаграммами конечных автоматов. Конечный автомат создается для композитной компоненты. Он использует сообщения и операции, определенные в интерфейсах компонент, для взаимодействия с окружением. В паре два этих типа диаграмм позволяют создавать содержательные и наглядные спецификации, по которым генерируется целевой код СРВ. Все это и хочется продемонстрировать.
На рис. 7.1 представлена диаграмма последовательностей, на которой обозначены главные действующие лица примера и основной сценарий их взаимодействия. Сразу после включения телефонной трубки (пользователь нажал нужную кнопку на аппарате) клавиатура (Keybroad), с помощью сообщения Switch-on, создает компоненту UserDriver, которая, в свою очередь, создает компоненту Main. После этого компонента UserDriver, с помощью сообщения DPINInput, посылает дисплею команду отобразить приглашение на ввод PIN. Введенный пользователем PIN пересылается с клавиатуры компоненте UserDriver, а та переправляет его компоненте Main, где происходит его проверка. Если PIN правильный, то компонента Main начинает искать сеть, посылая оповещение об этом
компоненте UserDriver (сообщение SearchForPLMN). Последняя, в свою очередь, командует дисплею отобразить картинку поиска сети (сообщение DSearchPLMN). Когда сеть найдена, Main посылает UserDriver сообщение HomePLMN, и та, после его получения, предлагает дисплею отобразить картинку-сообщение, что полный сервис телефона доступен пользователю (сообщение DHomePLMN). Компонента Main переходит в состояние Idle и готова обслуживать запросы пользователя телефона и входящие запросы из сети.

Рис. 7.1.
Главный сценарий примера
Из четырех сущностей, представленных на диаграмме с рис. 7.1, нас интересуют только две - UserDriver и Main. Оставшиеся не являются программным обеспечением2), поэтому здесь не рассматриваются. Компоненты UserDriver и Main представлены на рис. 7.12.
Рис. 7.2.
Компоненты Main и UserDriver
В нашем примере поведение компоненты Main определяется с помощью диаграммы конечных автоматов. Иллюстративный вариант этой спецификации представлен на рис. 7.3. Данная диаграмма создана для того, чтобы функциональность компоненты Main стала понятной в первом приближении: имена состояний и события обозначены по-русски, нет описания действий в переходах и т. д. Формальная спецификация поведения компоненты Main будет представлена ниже (нетерпеливые могут посмотреть уже сейчас на рис. 7.12). UML позволяет создавать такие промежуточные, эскизные спецификации и хранить их наравне с основными.
Рис. 7.3.
Иллюстративное описание поведения компоненты Main
Прокомментируем рис. 7.3. При включении трубки компонента Main переходит в состояние "Ожидание PIN". Если PIN введен верно, то далее компонента Main оказывается в состоянии "Поиск сети" и ищет свою сеть - ту, в которой абонент зарегистрирован и информация о которой хранится в его трубке. Если своя сеть найдена, то происходит переход в состояние "Ожидание запроса". В этом состоянии компонента Main способна обрабатывать запросы на установку соединения - как исходящего, от абонента трубки, так и входящего, поступившего из сети. Но эта функциональность уже отсутствует в нашем примере, дабы не усложнять его чрезмерно.
Это был самый "хороший" сценарий, в результате исполнения которого телефонная трубка включилась и готова обслуживать абонента. Теперь рассмотрим самый "плохой" сценарий, когда телефон есть, сеть есть, а позвонить никуда, кроме как в милицию, нельзя (гм, что может быть хуже…). В состоянии "Ожидание PIN" компонента Main может принять три попытки ввода неверного PIN. Если вторая или третья попытка окажется удачной, то дальнейшие события разворачиваются так, как описано выше. Если же и в третьей попытке был введен неверный PIN, то происходит переход в состояние "Ожидание PUK". В этом состоянии принимается десять попыток ввести верный PUK и после десятой попытки происходит переход в состояние "Блокирована". Если компонента Main находится в этом состоянии, то трубка может позволить абоненту сделать только экстренный выз
ов (милиция, скорая помощь), а также выключить трубку. Теперь
рассмотрим различные "боковые ветки", спецификации которых посвящен остаток диаграммы.
В состоянии "Ожидание PUK" пользователь может ввести правильный PUK, и после этого он снова получит возможность вводить PIN.
- В состоянии "Поиск сети", кроме того, что было рассказано, может произойти следующее.
- Своя сеть не найдена, но найдена чужая сеть. Сервис, который доступен абоненту в этом случае, будет зависеть от того, есть ли у него роуминг. Но компонента Main каждые 0,5 секунд будет проверять, не появилась ли своя сеть3).
- Не найдена никакая сеть. В этом случае компонента Main будет продолжать поиск сети.
В состояниях "Ожидание PIN", "Ожидание PUK", "Блокирована", "Чужая сеть" компонента Main обеспечивает абоненту обработку экстренного вызова и возвращается обратно в то состояние, в котором ее прервали. Наконец, в любом состоянии компонента Main способна обработать сообщение о выключении трубки, посланное пользователем с клавиатуры через компоненту UserDriver, и завершить свою работу.