Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> сделать UserSessionContext, как? 
:(
    Опции темы
sandello
Дата 18.9.2007, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 18.5.2005
Где: Пермь

Репутация: нет
Всего: 2



Есть JBossAS + EJB3. Есть бизнес логика, которая выполняется набором Session EJB на AS. Некоторые из этих бинов предоставляют «точку входа» в систему. Нужно сделать какой-то контекст, который будет один для  всего стека вызовов, начиная с точки входа.
Другими словами при «дерганьи» за эту точку входа создается какой-то контекст, к которому можно получить доступ из любого метода. При совершении вызова другого бина этот контекст распространяется туда. Т.е. если в первом бине в контекст положить значение, то во втором его можно добыть. При этом значения не будут никак пересекаться со значениями из «паралелльного» контекста (другой вызов точки входа).

Как можно решить такую задачу? Особенно в случае нескольких AS. Тривиальный вариант добавлять в этот контекст в качестве аргумента лучше не расматривать, интересно другое решение.


--------------------
user posted image
PM MAIL Jabber   Вверх
Maksym
Дата 18.9.2007, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



sandello
Singleton не проканает?
PM MAIL   Вверх
Stampede
Дата 18.9.2007, 18:18 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 66
Всего: 144



Цитата(Maksym @  18.9.2007,  06:33 Найти цитируемый пост)
Singleton не проканает? 


Нет, не проканает, потому что:

Цитата(sandello @  18.9.2007,  06:04 Найти цитируемый пост)
При этом значения не будут никак пересекаться со значениями из «паралелльного» контекста (другой вызов точки входа).


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

Код

public class SomeUtilityClass {
    private static ThreadLocal threadContext = new ThreadLocal() {
        protected synchronized Object initialValue() {
            return new Context();
        }
    };

    public static Context getThreadContext() {
        return (Context) threadContext.get();
    }
}


Пользуемся этим так: Maksym, узнаешь нечто знакомое?

Код

// где угодно
Context ctx = SomeUtilityClass.getThreadContext();
// делаем что угодно


Фсе, телемаркет! Теперь при помощи этой конструкции можно в абсолютно любом месте кода прямо из воздуха получать все, что "наложили" в этот контекст ранее отработавшие методы. Примерно таким образом, например, реализован прозрачный (без явной передачи аргументов) доступ к текущей транзакции в JPA.

Особенно хорошо понятие контекста потока ложится на идеологию SOA. Авторизация, например, превращается в сущий пустяк: в начале обработки аутентифицировал юзера, засунул его в контекст потока, и с этого момента и до конца обработки объект User у нас доступен любым алгоритмам авторизации доступа, где он может понадобиться.

Аналогичным образом можно передавать через воздух локали, настройки, да и просто все что угодно. В общем, возможности ограничиваются только твоей фантазией smile


Это сообщение отредактировал(а) Stampede - 18.9.2007, 18:26


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Maksym
Дата 18.9.2007, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


.
***


Профиль
Группа: Участник Клуба
Сообщений: 1456
Регистрация: 19.8.2005
Где: Odessa, Black Sea

Репутация: 24
Всего: 62



Цитата(Stampede @  18.9.2007,  18:18 Найти цитируемый пост)
Пользуемся этим так: Maksym, узнаешь нечто знакомое?

А то. smile  +1
PM MAIL   Вверх
sandello
Дата 19.9.2007, 06:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 18.5.2005
Где: Пермь

Репутация: нет
Всего: 2



Цитата(Stampede @  18.9.2007,  21:18 Найти цитируемый пост)
идеально подходит такая вешь как ThreadLocal

Я честно говоря не знаю, как JBoss поднимает и хранит запущенные бины... Но есть подозрение, что никто не гарантирует одного потока... особенно, если идут вызовы между бинами. Какой-то из них может оказаться удаленным. Второе, после окончания обработки моего запроса поток не умирает и нужно позаботиться, что бы этот контекст очистить.
Подозреваю, что задача в общем случае решения не имеет. Проще сделать руками - обеспечить передачу между бинами и складывание в ENV каждого бина.


--------------------
user posted image
PM MAIL Jabber   Вверх
mindflyer
Дата 19.9.2007, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.10.2004
Где: Smolensk, Russia

Репутация: 3
Всего: 4



В случае одного сервера задачу легко и удобно решить с помощью threadLocal контекста создаваемого и уничтожаемого в интерсепторе. Т.е. создаешь свой интерсептор, вешаешь его на SB (SessionBean) и все обращения к SB проходят через него. Если лень навешивать интерсепторы явно на все SB, то можно прописать в файл ejb3-interceptors-aop.xml. 
Все вызовы между бинами идут в одном потоке, поэтому проблем не будет. Если где-то тебе понадобиться запустить обработку в нескольких потоках, то просто скопируй контекст и в их threadLocal. Почистить не забудь smile

Для интерсептора прописываемого в ejb3-interceptors-aop.xml код будет такой:
Код

...
import org.jboss.aop.advice.Interceptor;
...
public class ContextInterceptor implements Interceptor {
...
   public Object invoke(Invocation invocation) throws Throwable {
        boolean isNewContext = Context.getContext() == null;
        if ( isNewContext ) 
                Context.setContext(new Context());
        try {
         return invocation.invokeNext();
        } finally {
        if ( isNewContext ) 
                Context.setContext(null);
        }
    }
}


Для явно указываемых в SB:
Код

@AroundInvoke
public Object process(final InvocationContext ctx) throws Exception {
        boolean isNewContext = Context.getContext() == null;
        if ( isNewContext ) 
                Context.setContext(new Context());
        try {
         return return ctx.proceed();
        } finally {
        if ( isNewContext ) 
                Context.setContext(null);
        }


Если контекст нужно передавать в другой сервер, то тут, конечно, сложнее. Между серверами я не делал, но реализовывал между клиентом и сервером (принципиальной разницы быть не должно). Объект invocation (из первого примера), который использует JBoss для вызовов SB, хранит метаинформацию (invocation.getMetaData(...)). Так вот, берём прописываем два интерсептора: один для вызывающей стороны - в ejb3-interceptors-aop.xml в стеки с именами "*ClientInterceptors", который будет сохранять контекст в метадату, и второй для принимающей стороны, который будет извлекать контекст и устанавливать его в threadLocal, у меня он прописан примерно так:
Код

...
<interceptor name="Td2SecurityContextInterceptor" class="net.uk.topdog.td2.security.server.interceptor.SecurityContextInterceptor" scope="PER_VM"/>
...
 <domain name="Stateless Bean">
      <bind pointcut="execution(public * *->*(..))">
...
         <interceptor-ref name="Td2SecurityContextInterceptor"/>
...
      </bind>
...

Плюс в другие домены рядом с "<interceptor-ref name="org.jboss.ejb3.security.AuthenticationInterceptorFactory"/>". Причину сейчас уже не помню.

Таким образом можно осуществить передачу в одну сторону. В обратную сторону я не делал, но немного исследовал этот вопрос и увидел, что JBoss для передачи в обратную сторону использует invocation.getResponseContextInfo(). Так что и здесь проблем быть не должно.

PM MAIL ICQ   Вверх
sandello
Дата 19.9.2007, 10:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 18.5.2005
Где: Пермь

Репутация: нет
Всего: 2



Цитата(mindflyer @  19.9.2007,  12:59 Найти цитируемый пост)
Если лень навешивать интерсепторы явно на все SB

По смыслу задачи,  threadLocal нужно чистить только при клиентском вызове. Поэтому на все SB нельзя. Только на те, что торчат интерфейсами наружу. Проблема будет для бинов, которые обрабатывают и внешние (контекста еще нет, нужно чистить/создавать), и внутренние (контекст чистить _нельзя_).
Если нет передачи между вызовами, то контекст лепить вообще нет необходимости: штатный java:comp/env дает все что нужно (или я ошибаюсь?).

Цитата(mindflyer @  19.9.2007,  12:59 Найти цитируемый пост)
один для вызывающей стороны - в ejb3-interceptors-aop.xml в стеки с именами "*ClientInterceptors"

Можешь про это подробнее? Где почитать?

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

Это сообщение отредактировал(а) sandello - 19.9.2007, 10:17


--------------------
user posted image
PM MAIL Jabber   Вверх
mindflyer
Дата 19.9.2007, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.10.2004
Где: Smolensk, Russia

Репутация: 3
Всего: 4



Цитата(sandello @  19.9.2007,  10:13 Найти цитируемый пост)
Проблема будет для бинов, которые обрабатывают и внешние (контекста еще нет, нужно чистить/создавать), и внутренние (контекст чистить _нельзя_).

Пусть интерсептор и проверяет требуется ли создание контекста. Как в приведённом мною примере.

Цитата(sandello @  19.9.2007,  10:13 Найти цитируемый пост)
Цитата(mindflyer @  19.9.2007,  12:59 Найти цитируемый пост)
один для вызывающей стороны - в ejb3-interceptors-aop.xml в стеки с именами "*ClientInterceptors"
Можешь про это подробнее? Где почитать?

Почитать можно на сайте JBoss про EJB3 и AOP. Точных ссылок не помню, да и бОльшую часть информации выяснял экспериментально.
Там всё достаточно просто, возьми для примера один из интерсепторов прописанных в том файле, и напиши свой по аналогии.
PM MAIL ICQ   Вверх
sandello
Дата 30.1.2008, 07:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 18.5.2005
Где: Пермь

Репутация: нет
Всего: 2



Решение, честно говоря, выглядит как затычка, за которой надо очень хорошо присматривать.... Ибо может не сработать.
Думаю просто тупо добавить еще один аргумент в каждый бизнес метод бина. А остальное можно и аспектами доделать.


--------------------
user posted image
PM MAIL Jabber   Вверх
mindflyer
Дата 30.1.2008, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 113
Регистрация: 20.10.2004
Где: Smolensk, Russia

Репутация: 3
Всего: 4



А что именно не нравится?  И почему может не сработать? У нас этот код написан полтора года назад, и с тех пор ни разу к нему не возвращались. Собственно, кроме меня в нашей команде никто и не знает как это работает - потому что никому и не нужно это знать, всё работает прозрачно и стабильно.
По-умолчанию, контекст создаётся для абсолютно всех вызовов EJB SB, в нём устанавливается id клиентского приложения, текущий пользователь, ряд дополнительных характеристик. Сам id приходит с клиента в invocation.getMetaData(). Этот id пишется в логи в каждую запись, создаваемую в рамках обработки запроса от клиента. Что, как ты сам заметил в соседней теме, очень удобно.  Плюс есть ряд других контекстов, расширяющих дефолтовый, для обработки специфических запросов. 

Если тебя смущают интерсепторы, то можно просто создавать/уничтожать те же самые ThreadLocal контексты руками в точке входа запроса. Если таких точек немного, то и такой вариант прокатит. Но, ИМХО, вот это уже точно сложнее отслеживать, чем в предлагаемом мною решении.
У нас есть один use-case, где жизненный цикл контекста контролируется явным образом в SFSB - но там такая специфика, что он должен жить именно всё время жизни SFSB. Да и там для обработки клиентского запроса стартует множество потоков, в каждом из этих потоков в threadLocal устанавливается ссылка на этот контекст (тоже прозрачным способом, используя наше расширение ThreadPoolExecutor) - и каждый поток складывает результаты работы в этот контекст.

Так что слова про затычку мне не понятны. Постановка задачи у тебя - добавить одинаковую обработку для всех клиентских запросов - а ведь интерсепторы именно для этих целей и используются в jboss. И, кстати, реализованы именно через AOP smile
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0823 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.