Я не совсем уверен, что понимаю ваш вопрос, но в основе его лежит проблема параллелизма, позволяющая нескольким клиентам одновременно изменять состояние службы.
Насколько я понимаю, у вас есть клиент, который позволяет пользователю просматривать состояние системы (ваше моделирование) и изменять его. На стороне клиента у вас есть MVC, основанный на событиях, где слушатель ожидает изменений из пользовательского интерфейса, а затем передает изменения клиенту, который уведомляет сервер. В очень элементарном смысле, как это:
Today:
-------- ------------------ ----------
| UI | - change event -> | Event Listener | - set value -> | Server |
-------- ------------------ ----------
Если я правильно понимаю предложенное вами решение, вы хотите перехватить эти события и сначала спросить сервер, если кто-то недавно изменил состояние, прежде чем пытаться внести изменения.
Proposed:
-------- ------------------ ------------------ ----------
| UI | - change event -> | Proxy Listener | - event -> | Event Listener | - set value -> | Server |
-------- ------------------ ------------------ ----------
|
timestamp
|
v
----------
| Server |
----------
На мой взгляд, это не идеальное решение по разным причинам. Во-первых, вы говорите с сервером дважды. Во-вторых, вам необходимо выяснить, как создавать прокси для различных типов обработчиков событий, о которых вы упоминали в разделе «Как узнать, какой метод вызывать». Это потребует либо нескольких различных реализаций прослушивателя прокси, либо некоторой очень грязной рефлексивной логики. (Скорее всего, это можно сделать с помощью динамических прокси-серверов.) Наконец, вам нужно полагаться на то, что прослушиватель прокси-сервера добавляется каждый раз, поэтому одновременная безопасность не используется по умолчанию.
Я думаю, что более общее решение, которое может быть применено к вашим текущим вариантам использования и любым будущим расширениям, будет заключаться в том, чтобы сделать вызов установленного значения безопасным для сервера. То есть Сервер должен определить, когда прослушиватель событий пытается внести изменения в значение, которое является актуальным (иначе: значение устарело), и, в этом случае, отказаться от внесения этого изменения. В этом случае необходимо решить две небольшие проблемы: как обнаружить изменение в устаревшем состоянии и, во-вторых, как сообщить клиенту, что изменение не было выполнено.
Для первой проблемы вы можете захотеть реализовать некоторую форму оптимистической блокировки. Как и в предложенном вами решении, вы можете использовать временные метки для этого. Например, когда пользовательский интерфейс рендерится, он получит значение с сервера. Сервер может передать обратно значение, а также отметку времени последнего изменения этого значения. Когда пользователь вносит изменение, клиент передает новое значение на сервер и исходную последнюю измененную временную метку. (т. е. «Сервер, установите foo равным 10 и последний раз, когда кто-то изменил foo, был вчера.») Затем сервер узнает, соответствует ли ваше изменение самому последнему значению, и если нет, может отказаться от изменения.
Если у вас нет возможности хранить последнюю измененную временную метку с каждым изменяемым значением, вы можете выполнить то же самое с помощью хеша. Когда сервер возвращает значение клиенту, рассчитайте и верните хеш со значением. Когда сервер получает запрос на обновление, клиент передаст обратно хэш, и сервер сможет пересчитать хеш из значения, которое он имеет. Если они совпадают, то изменение клиента относится к самому последнему значению.
(Терминологическое предупреждение: используете ли вы временную метку или хэш, это значение служит «мьютексом».)
Вы не предоставляете много подробностей о том, как взаимодействуют клиент и сервер, поэтому я могу только догадываться об их интерфейсе, но если у сервера есть возможность отслеживать клиентов в сеансах на стороне сервера, вы может выполнить работу по сохранению и предоставлению соответствующего значения мьютекса полностью на стороне сервера. В этом случае сервер отслеживает, какие значения он предоставил конкретному клиенту для данного сеанса и каковы были значения мьютекса. Когда клиент возвращается с запросом на обновление в том же сеансе, сервер может найти мьютекс для этого значения и выполнить соответствующее действие, даже если клиент даже не осознает, что сервер делает это. В этом случае вы можете принудительно применять безопасный для параллельного кода код, не меняя своего клиента по сравнению с тем, как он выглядит сегодня.
Что касается второй проблемы, касающейся того, как уведомить клиента о том, что изменение было отклонено, поскольку оно устарело, это должно быть относительно легко в зависимости от того, как взаимодействуют ваш клиент и сервер. Если вы используете какой-либо SOAP или RPC, который допускает удаленные исключения, я бы рекомендовал вам отбросить что-то похожее на Java ConcurrentModificationException. В этом случае все, что вам нужно сделать, это просмотреть, перехватить исключение и обработать его соответствующим образом. Это, скорее всего, означает повторный вызов сервера для получения наиболее актуального значения и, вероятно, уведомление пользователя о том, что запрошенное обновление не было принято, поскольку состояние моделирования изменилось из-под них.