Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
Вызов метода HandleWorkCompletion должен выполнить некоторую подготовительную работу к выполнению следующей работы из очереди работ. Мы рассмотрим этот метод позже. Сейчас же следует начать с начала, т. е. рассмотреть весь процесс перехвата вызова и включения его в очередь (или, в некоторых случаях, исполнения без включения в очередь).
Перехват входящего вызова
Формирование
Класс SynchronizationAttribute реализует интерфейс IContributeServerContextSink. Благодаря этому факту, при формировании нового контекста синхронизации (в новом или в старом домене синхронизации) автоматически вызывается метод GetServerContextSink, объявленный в данном интерфейсе, для формирования перехватчика входящих вызовов для данного контекста. Ниже приводится код этого метода из Rotor:
public virtual IMessageSink GetserverContextsink {
IMessageSink nextSink) {
InitlfNecessary;
SynchronizedServerContextSink propertySink =
new SynchronizedServerContextSink (
this,
nextSink);
return (IMessageSink) propertySink;
}
Единственным входным параметром является ссылка на перехватчик, последний на данный момент в цепочке перехватчиков входящих вызовов для данного контекста. Возвращаемое значение является ссылкой на новый перехватчик, который будет добавлен в эту цепочку.
Прежде всего выполняется инициализация свойства синхронизации, если это необходимо. Метод InitIfNeccessary был рассмотрен ранее. Реально он будет выполнять инициализацию свойства синхронизации только в том случае, когда текущий контекст является первым контекстом домена синхронизации. В противном случае свойство синхронизации уже было инициализировано ранее.
Далее формируется экземпляр класса SynchronizedServerContextSink, который будет рассмотрен позже. Этот объект и будет выступать в роли перехватчика входящих вызовов. Ему передаются два параметра:
• this— ссылка на свойство синхронизации (экземпляр данного класса SynchronizationAttribute) — новое или ранее сформированное, живущее в первом контексте домена синхронизации
• nextsink — ссылка на следующий в цепочке перехватчик.
И, наконец, возвращается полученная ссылка на новый перехватчик.
Таким образом, хотя свойство синхронизации одно на весь домен синхронизации, для каждого контекста в этом домене формируется свой перехватчик, имеющий ссылку на это свойство синхронизации.
Как перехватчик обрабатывает синхронные вызовы
Теперь рассмотрим класс SynchronizedServerContextSink:
internal class SynchronizedServerContextSink
: InternalSink, IMessageSink {… }
Мы видим, что данный класс наследует классу InternalSink и реализует интерфейс IMessageSink. Класс InternalSink отсутствует в .NET. Интерфейс IMessageSink объявляет методы, которые должны быть реализованы перехватчиками всех типов.
Класс SynchronizedServerContextSinkсодержит два поля данных:
internal IMessageSink _nextSink;
internal SynchronizationAttribute _property;
Первое содержит ссылку на следующий перехватчик, а второе — на свойство синхронизации текущего домена синхронизации.
Единственный конструктор инициирует эти поля:
internal sSynchronizedServerContextSink (
SynchronizationAttribute prop,
IMessageSink nextSink) {
_property = prop;
_nextSink = nextSink
}
Каждый перехватчик должен обеспечить обработку как синхронных, так и асинхронных вызовов. Соответствующие методы объявлены в интерфейсе IMessageSink. Это SyncProcessMessage и AsyncProcessMessage.
В данном перехватчике обработка синхронных вызовов осуществляется следующим образом:
public virtual IMessage SyncProcessMessage(IMessage reqMsg) {
Workitem work = new Workitem(reqMsg,
_nextSink, null);
_property.HandleWorkRequest(work);
return work.ReplyMessage;
}
Собственно вызов в форме сообщения типа IMessage передается как единственный входной параметр. Возвращаемое значение (также типа IMessage) содержит результат, полученный данным перехватчиком от следующего в цепочки перехватчика после того, как вызов пройдет через всю цепочку перехватчиков до сервера, будет обработан на сервере, а ответ от него пройдет через всю цепочку перехватчиков в обратном направлении до данного перехватчика. Тут надо заметить, что на этом пути в каком-либо промежуточном перехватчике вызов может быть преобразован в асинхронную форму.
Роль данного перехватчика состоит в инкапсуляции вызова в объект типа WorkItem и его сохранении в очереди работ. Для этого вызывается конструктор WorkItem (reqMsg, _nextSink, null), первые два параметра которого задают вызов в форме сообщения и ссылку на следующий перехватчик. Третий параметр используется только в случае асинхронных вызовов. По умолчанию инкапсулирующая вызов работа work относится к синхронному типу.
После инкапсуляции вызова соответствующая работа передается свойству синхронизации: